fattwam Posted November 22, 2007 Report Posted November 22, 2007 A technical guide to Halo 2 Scripts v2.0A tutorial by Soldier of LightWith help by Shalted, The Tycko Man, Doom, and Killing for Fun.With added information by Agent ME. Included Files:This Word Document should have been packaged in a compressed file with the following files:Script list.txt Has list of commands with numbers and legal value typesValue type.txt Has an updated list of value typesDb.txt Has a list of commands with the value types of the arguments Not formatted extremely well for easy viewingSamples.zip Zip file of various scripts and compiled hex to demonstrateconcepts If you downloaded this file without the other listed files, please redownload the latest version of this package at http://am37.frih.net/ Table of Contents:a) section breakdownB) syntax explanationc) global dissection Ã?¢ââ??‰â?¬Å? real exampled) decompilinge) compilingf) advanced stuffg) credits A) Section Breakdown Halo 2 scripts are a very complex system. They exist solely in the scnr tag, and are able to run in single and multiplayer maps. They are the single most powerful tool in the game, able to edit almost any property on the fly. So without further ado, letÃ?¢ââ??‰â??¢s get on into how they are structured. There are 4 main reflexives involved with the scripts (in order of appearance):String tableScript namesGlobalsSyntax data Brief descriptions of each of them:The string table lists every single string used in the scripts. Useless for the most part, unless youÃ?¢ââ??‰â??¢re doing quick editing or decompiling. The engine uses numbers instead of strings to determine what command itÃ?¢ââ??‰â??¢s running. The script names lists all of the names, types, and return values of the scripts in the map. It contains the data for the script header: Ã?¢ââ??¬Ã?â??(script type nameÃ?¢ââ??¬Ã?Â. It also tells the game where (in the syntax data) to find the commands for the script. The globals reflexive lists all of the global variables for the map, along with their type. It tells the game where to find the initialization expression, which gives it a default value. Together, these create a global expression: Ã?¢ââ??¬Ã?â??(global type name value)Ã?¢ââ??¬Ã?Â. The syntax data is the most complex part of the scripting process. For now, just know that this is where most of the work occurs. B) Syntax Explanation First, you should take a look at existing game scripts in Halo2, and maybe even check out Halo Custom Edition scripts, and get an idea of how they work. You can use KillingForFunÃ?¢ââ??‰â??¢s Script decompiler (from http://www.haloplugins.com/forums/index.php?showtopic=226 ) to decompile existing Halo2 scripts from maps. Before we get to the rest, thereÃ?¢ââ??‰â??¢s a concept youÃ?¢ââ??‰â??¢ll need to understand first Ã?¢ââ??‰â?¬Å? the sibling and child relationships. Consider the following code: (script dormant childs_and_sibs (begin (physics_set_gravity 0.2) (print Ã?¢ââ??¬Ã?â??gravity is .2 now!Ã?¢ââ??¬Ã?Â)) ) Every syntax chunk, which in this script is every starting (, every command name, number, and string (strings are text), has a sibling. Every ( also has a child. Closing parenthesis ) do not have a syntax chunk Ã?¢ââ??‰â?¬Å? they are specified by the previous chunk by having no siblings. The sibling of every chunk is the next chunk, and counting parenthesis and everything in them as a single item. So sibling of Ã?¢ââ??¬Ã?â??beginÃ?¢ââ??¬Ã? is the ( in the 3rd line. The the sibling of the ( in the 3rd line would be the ( in the 4th line.The sibling of Ã?¢ââ??¬Ã?â??physics_set_gravityÃ?¢ââ??¬Ã? is 0.2.0.2 in line 3 has no sibling.The ( in the 4th line has no sibling. Childs of ( are the first syntax chunk on the inside of them.The child of ( in the 2nd line is Ã?¢ââ??¬Ã?â??beginÃ?¢ââ??¬Ã?Â.The child of ( in the 3rd line is Ã?¢ââ??¬Ã?â??physics_set_gravityÃ?¢ââ??¬Ã?Â. Hopefully now you understand siblings and childs in the syntax. If you donÃ?¢ââ??‰â??¢t, you might want to re-read the past section, or continue reading in hopes that you understand it eventually. I (Agent ME) didnÃ?¢ââ??‰â??¢t understand anything in SoLÃ?¢ââ??‰â??¢s tutorial at all until about the 5th time I read it. Scripting is a very complex subject. Now to continue to the technical stuff. The first three reflexives have very simple structures, and I will explain them as I go. But first I must explain the syntax data. The syntax data is a reflexive with 20 byte chunks. It can have padding anywhere inside of it, including the beginning, middle, and end, all seen in halo maps. Padding is denoted by 0000 followed by 18 bytes of BA. The structure of this reflexive is as follows: struct syntax { short expression index short identity short value type short expression type int sibling pointer int string table offset int value} A quick explanation of each value:Expression index Ã?¢ââ??‰â?¬Å? Each chunk of syntax data has an expression index. This value tells the game its location in the syntax data. The first chunk of syntax data will always have expression index 73E3. Usually there are 4 or 5 padding chunks before any actual data, so the first expression index you will actually see will usually be 77E3 or 78E3. Padding chunks have 0000 as their expression index to indicate that they serve no purpose. The next three values occur in reverse generality. The most general is last, and the most specific is first. I will list them in the order they appear. Identity Ã?¢ââ??‰â?¬Å? A value used by the engine to determine a specific command or object type. Every function in the game has a unique identity assigned to it, and it is the same between maps. For instance, Ã?¢ââ??¬Ã?â??sleepÃ?¢ââ??¬Ã? is command number 19. There is a list included with all commands, identities, and return types. Value Type Ã?¢ââ??‰â?¬Å? This value determines what type of expression weÃ?¢ââ??‰â??¢re looking at. For example, if this value is a 2, then we are looking at a function. If it is a 7, weÃ?¢ââ??‰â??¢re looking at a short. If weÃ?¢ââ??‰â??¢re looking at a 44, then itÃ?¢ââ??‰â??¢s a difficulty. There is also a list of these values included. NOTE: When youÃ?¢ââ??‰â??¢re using a command that returns a value, remember to set the command itself to have value type 2 (function), but set the value type of the opening parentheses immediately preceding the command itself. Expression Type Ã?¢ââ??‰â?¬Å? This value tells the game how to use the expression. There are very few values, the main ones being 8 and 9. 8 means that it is a syntax chunk Ã?¢ââ??¬Ã?â??(Ã?¢ââ??¬Ã?â??, and 9 means it is a statement chunk. 13 (0xD) is used for globals, and 10 (0xA) is used for referencing another script from inside a script. More on those later. Sibling Pointer Ã?¢ââ??‰â?¬Å? This value points to the next expression inside a set of parenthesis. It consists of 2 shorts, which work much the same way as dependency pointers. The second value is the expression index of the chunk it is pointing to, and the first value is the difference between that and 73E3 (the chunk number). Script table offset Ã?¢ââ??‰â?¬Å? Very simple. This int tells the game how many bytes into the string table the specific string for this expression is. This value is not necessary, and will not affect the way the script runs. Value Ã?¢ââ??‰â?¬Å? This value is pretty simple. When the expression type of a chunk is 8, this value will point to the first child inside the parenthesis. Otherwise, this value changes based on the value type of the chunk. For example, if the chunk is a real number, it will be a 4 byte float. If itÃ?¢ââ??‰â??¢s a reference to an object, it will be a chunk number or dependency. C) Global Dissection Ã?¢ââ??‰â?¬Å? real example Alright, now that weÃ?¢ââ??‰â??¢re through the structure of the syntax data, how do we use it? LetÃ?¢ââ??‰â??¢s start with something simpler: a global. It has the same basic structure as a script command, but itÃ?¢ââ??‰â??¢s simpler. LetÃ?¢ââ??‰â??¢s start in the globals reflexive. WeÃ?¢ââ??‰â??¢ll use elongation for its simplicity. This reflexive contains a 32 byte name, a 4 byte type, and a 4 byte expression pointer. LetÃ?¢ââ??‰â??¢s dissect this particular one:Name: k_crate_spacing.Type: 0700 0000 = short.Exp. Pointer = 0400 77E3. Great, so now what? Now we follow the expression index into the syntax data. We look at chunk number 4 (counting from 0), whose expression index is 77E3. Fortunately for us, bungie separates different scripts and globals using some padding, so itÃ?¢ââ??‰â??¢s not too hard to find by hand. This is how this particular expression looks in hex:77E3 0700 0700 0900 FFFF FFFF 2100 0000 9001 FFFF Now letÃ?¢ââ??‰â??¢s dissect this. The 77E3 is the expression index, which was used to find the expression. It has type 9, which means itÃ?¢ââ??‰â??¢s an expression. It has value type 7, which means itÃ?¢ââ??‰â??¢s a short, and its identity is also 7, which means itÃ?¢ââ??‰â??¢s declared here, not by another function. We can skip the pointer, since it has no siblings. Next we come to the script table pointer, but since this is a global with a short value, we ignore it (not sure why thereÃ?¢ââ??‰â??¢s anything there). Then we come to its value, 9001 (hex) = 400 (dec). This is the time between crate drops in elongation. Yay! Now you see how I did my first script mod. The simple 2 byte change was changing the 9001 to 3C00 (100). Not so simple anymore, huh. D) Decompiling Alright, you made it through the easy stuff. Now comes the part thatÃ?¢ââ??‰â??¢s sooo tedious it has to be automated. So now letÃ?¢ââ??‰â??¢s start decompiling a script. For this example I will be using the crate_eraser script from elongation. We start in the script names reflexive. The structure of this is remarkably similar to that of the globals reflexive, with one difference. It still has the same 32 byte name, followed by a 2 byte type, a 2 byte return type, and a 4 byte expression pointer. In this reflexive, the return type is the same as the type from globals. The type here is slightly different. All of the types for a script are as follows:0 = startup1 = dormant (called using wake)2 = continuous3 = static (called normally, using (command), and can have a return type)4 = stub (does nothing)5 = command_script (used to command ai players) For this script, here is the information: Type: 0200 = continuousReturn type: 0400 = voidExp. Pointer = 8500 F8E3Which becomes:Ã?¢ââ??¬Ã?â??(script continuous crate_eraserÃ?¢ââ??¬Ã?Â*note* the return type is not present in the header. Now we follow the root expression index of the script names reflexive into the syntax data. HereÃ?¢ââ??‰â??¢s where the differences begin. We no longer have such simple expressions. When dealing with commands in the syntax data, itÃ?¢ââ??‰â??¢s important to note that before every function name, there is an expression of type 8, which serves to specify the bounds of the expression. Basically, the expression will continue until it encounters its next sibling. So naturally, when we follow the root expression index, we find a type 8 expression. However, this is different from most in that it does not have any function following those contained within it. This is the begin expression, and contains all of the expressions in a script. So without further ado, letÃ?¢ââ??‰â??¢s delve in. The first expression in this script looks like:F8E3 0000 0400 0800 FFFF FFFF 2006 0000 8600 F9E3 Now we dissect. Notice itÃ?¢ââ??‰â??¢s type 8, its value type is void, and its identity is 0. These numbers tell us that itÃ?¢ââ??‰â??¢s the syntax statement for the begin function. YouÃ?¢ââ??‰â??¢ll notice that this chunkÃ?¢ââ??‰â??¢s value type is void, but there are still numbers in its value position. Since this is a type 8 function, these are a pointer to its child commands. It has no siblings, so its sibling pointer is FFFF FFFF, and this expression will be closed when the main script is closed. F9E3 0000 0200 0900 7500 E8E3 0000 0000 0000 0000Notice that the previous statement had a child pointer of F9E3 and this begins with F9E3. This is how you navigate through the syntax data: by following child and sibling pointers. Now letÃ?¢ââ??‰â??¢s dissect this piece of data. Here we have a type of 9, meaning itÃ?¢ââ??‰â??¢s a statement. A value type of 2 means itÃ?¢ââ??‰â??¢s a function, and an identity of 0 means itÃ?¢ââ??‰â??¢s begin. Note that you could also follow the string offset to find out that itÃ?¢ââ??‰â??¢s begin, but the engine actually uses the identity value. So our script stands at: (script continuous crate_eraser (begin Since this expression is a statement, it canÃ?¢ââ??‰â??¢t have any children, so we follow its sibling pointer to our next command. E8E3 3400 0400 0800 7D00 F0E3 5606 0000 7600 E9E3LetÃ?¢ââ??‰â??¢s have a look at this. Right off the bat we see that itÃ?¢ââ??‰â??¢s type 8, which means syntax expression. Value type 4 means its value is void. And identity 3400 means that its child command has identity 3400. Now we get into some more complicated things. You see that it has both a child and sibling pointer. WeÃ?¢ââ??‰â??¢re going to follow the child pointer first, and come back to the sibling later. IÃ?¢ââ??‰â??¢m gonna start going faster now. E9E3 3400 0200 0900 7700 EAE3 0201 0000 0000 0000We follow its child pointer to this expression. ItÃ?¢ââ??‰â??¢s a function statement, with function identity 3400. Since I donÃ?¢ââ??‰â??¢t know what is offhand, I follow its string offset to find that itÃ?¢ââ??‰â??¢s Ã?¢ââ??¬Ã?â??object_destroyÃ?¢ââ??¬Ã?Â. So that means that this line begins with: (object_destroyBut what comes after? To find out, we follow its sibling pointer. Note that its sibling is inside the same set of parenthesis. EAE3 2500 3200 0800 FFFF FFFF 6606 0000 7800 EBE3Here we have another type 8, which is a syntax expression. That means we have another function coming up. But whatÃ?¢ââ??‰â??¢s thisÃ?¢ââ??¬Ã?¦ the value type isnÃ?¢ââ??‰â??¢t 4? It doesnÃ?¢ââ??‰â??¢t give a void result? No, this time the function is the argument of another, and it actually returns something. 3200 = scenery_name. And 2500 is the identity of the function we will be using. But since there will be no sibling for this function, its sibling pointer is nulled. ThatÃ?¢ââ??‰â??¢s alright, IÃ?¢ââ??‰â??¢ll explain it when we reach the end. LetÃ?¢ââ??‰â??¢s look at what we have so far: (object_destroy (ItÃ?¢ââ??‰â??¢s coming along. So letÃ?¢ââ??‰â??¢s go and follow the child pointer. EBE3 2500 0200 0900 7900 ECE3 1101 0000 0000 0000Another type 9 statement, another command, this time identity 2500 = Ã?¢ââ??¬Ã?â??list_getÃ?¢ââ??¬Ã?Â. Add that string in, and we have: (object_destroy (list_getFollow the sibling pointer to the next one. ECE3 2300 1F00 0800 7C00 EFE3 7006 0000 7A00 EDE3Another type 8 expression, another open parenthesis. This time the value type is 1F00 = object_list. Add this in, and hereÃ?¢ââ??‰â??¢s our line so far: (object_destroy (list_get (Getting pretty complex. LetÃ?¢ââ??‰â??¢s keep going, starting with children. EDE3 2300 0200 0900 7B00 EEE3 1A01 0000 0000 0000Type 9 statement, itÃ?¢ââ??‰â??¢s a function, identity 2300 = volume_return. Line is now: (object_destroy (list_get (volume_returnKeep going on to its sibling. EEE3 0D00 0D00 0900 FFFF FFFF 3001 0000 0100 0000Type 9 statement. 0D00 = trigger_volume. If you follow the string back to the table, youÃ?¢ââ??‰â??¢ll see the name of the volume, but the game doesnÃ?¢ââ??‰â??¢t use that. The game uses the value here, which is an index. WeÃ?¢ââ??‰â??¢re using chunk 1 of the trigger volumes reflexive. Its name is tv_crate_eraser_left. Notice that thereÃ?¢ââ??‰â??¢s no more pointers here! What does that mean? That means that we put the close parenthesis here. So put it together and we get: (object_destroy (list_get (volue_return tv_crate_eraser_left)*phew* almost done with this line. LetÃ?¢ââ??‰â??¢s keep going. To continue, we go back to the last open parenthesis, which opened the list_get command, and follow its sibling pointer. EFE3 0700 0700 0900 FFFF FFFF 9D06 0000 0000 FFFFAlright, type 9 statement, value type 0700 = short. Again, notice no more pointers. If you go back to the opening for object_destroy, thereÃ?¢ââ??‰â??¢s your next sibling pointer. However, IÃ?¢ââ??‰â??¢m going to stop here. HereÃ?¢ââ??‰â??¢s the whole line: (object_destroy (list_get (volume_return tv_crate_eraser_left) 0))Add it into what we got before, and the first 3 lines of our script are:(script continuous crate_eraser (begin (object_destroy (list_get (volume_return tv_crate_eraser_left) 0)) Wow!! ThatÃ?¢ââ??‰â??¢s a lot of work for one line. Now you see why we need a program for this. If you want, you can continue this pattern to decompile the rest of the script, but IÃ?¢ââ??‰â??¢m going to move on to compiling now. E) Compiling Phew, thatÃ?¢ââ??‰â??¢s a lot of work. Now are you ready for the final task: Compiling? I hope so, because this is probably what you read the tutorial for. Please, if you skipped straight to compiling, go back and read the rest, youÃ?¢ââ??‰â??¢re going to need it to understand this. If youÃ?¢ââ??‰â??¢ve read the rest, then letÃ?¢ââ??‰â??¢s jump right in. For this tutorial, IÃ?¢ââ??‰â??¢m not going to do the public example that you all know, the zero gravity terminal, mainly because there was too much guesswork involved on my part, and too many mistakes. Therefore, IÃ?¢ââ??‰â??¢m going to walk you through a very similar script on coagulation. The script we will be using looks like: (script startup gravity_hack (begin (physics_set_gravity 0.5) )) Now, before we start writing out the syntax data, we need to set up the rest of our map. LetÃ?¢ââ??‰â??¢s start by adding the chunk we need. If you open up entity, and go to the chunk adder, we need to inject a single chunk named Ã?¢ââ??¬Ã?â??ScriptsÃ?¢ââ??¬Ã? from a map with scripts into our coagulation. ItÃ?¢ââ??‰â??¢s easiest from elongation, because it only has 3 chunks, so itÃ?¢ââ??‰â??¢s faster to delete the others. We will edit this chunk at the end of the tutorial. Quick walkthrough:1) Open elongation2) Open the scnr tag3) Right-click the references section, and click clone chunk4) Find the Ã?¢ââ??¬Ã?â??ScriptsÃ?¢ââ??¬Ã? reflexive, click it, and click copy to clipboard.5) Close elongation, open coagulation.6) Open the scnr tag7) Right-click the references section, and click clone chunk. Click the parent chunk (it should say header, then one child chunk, click that) and click Ã?¢ââ??¬Ã?â??add to selected reflex/chunk.Ã?¢ââ??¬Ã?Â9) Navigate to the new Ã?¢ââ??¬Ã?â??ScriptsÃ?¢ââ??¬Ã? reflexive, open it, click the first chunk, and click delete.10) Repeat step 9.11) Click add meta to map. Alright, now we have our reflexive and chunk in coag. The next step is not actually necessary, but is a good practice to get into. WeÃ?¢ââ??‰â??¢re going to add our strings to the string table. You can use entity to get the offset for it. Once there in the hex editor, youÃ?¢ââ??‰â??¢re going to overwrite the (decorator_rebuild_all with Ã?¢ââ??¬Ã?â??beginÃ?¢ââ??¬Ã? followed by a null byte (00) followed by Ã?¢ââ??¬Ã?â??physics_set_gravityÃ?¢ââ??¬Ã? followed by a null byte. If you choose not to do this step, the script will still run, but will not be decompiled properly by our tools. DonÃ?¢ââ??‰â??¢t think that this is a way to add security to your scripts however, because they can still be decompiled using the command identity list. Now we start writing the syntax data. Following the example set by Bungie, weÃ?¢ââ??‰â??¢re going to do 2 strange practices: Leave padding chunks before and after scripts, and place the begin statement at the end. Since weÃ?¢ââ??‰â??¢re putting Ã?¢ââ??¬Ã?â??beginÃ?¢ââ??¬Ã? at the end, that means our first line is actually going to be Ã?¢ââ??¬Ã?â??(physics_set_gravity 0.5)Ã?¢ââ??¬Ã?Â. So the first thing we have to do is navigate to the syntax data, and find where weÃ?¢ââ??‰â??¢re going to inject this script. Once youÃ?¢ââ??‰â??¢ve located the beginning of the syntax data (note that it begins with 0000, not with BABA) weÃ?¢ââ??‰â??¢re going to skip ahead 4 chunks to do our injecting. That means you should be 80 bytes past the start of the reflexive before you insert any data. An important thing to mention here is that weÃ?¢ââ??‰â??¢re not actually adding any bytes to the map, only overwriting. The syntax data is padded to a certain amount (516 chunks). You only add more if you run out of space, and you only add 516 more padding chunks to be overwritten. Alright, now letÃ?¢ââ??‰â??¢s start writing our expression. We begin with the Ã?¢ââ??¬Ã?â??(Ã?¢ââ??¬Ã?â?? of the physics_set_gravity command. We have all of the info we need about it, so letÃ?¢ââ??‰â??¢s start writing it. We start with the expression index. Since we left 4 chunks of padding, our first expression index will be 77E3. Next comes the 3 types. IÃ?¢ââ??‰â??¢m going to go in reverse order for logicÃ?¢ââ??‰â??¢s sake. Starting with the expression type, itÃ?¢ââ??‰â??¢s type 8 because itÃ?¢ââ??‰â??¢s a syntax expression. Going backwards to value type, itÃ?¢ââ??‰â??¢s a void value. Then we need the identity for physics_set_gravity which is 7F00. So our first 4 bytes should be like this:77E3 7F00 0400 0800 Good, now letÃ?¢ââ??‰â??¢s move on. If you look at the script, the () for physics_set_gravity does not have any siblings after it, so we add a null pointer here (FFFF FFFF). Then we have the table pointer, and since this is a syntax expression, it doesnÃ?¢ââ??‰â??¢t reference the table. Bungie uses random values, but itÃ?¢ââ??‰â??¢s just easier to use 0000 0000. And now comes the child reference. Since the next chunk will have expression index 78E3, our child reference looks like this: 0500 78E3. So hereÃ?¢ââ??‰â??¢s the first full chunk:77E3 7F00 0400 0800 FFFF FFFF 0000 0000 0500 78E3. Yay, weÃ?¢ââ??‰â??¢re making progress. Continuing on, we write out the next expression. Its expression index will be 78E3. Its 3 types (in reverse order) are 0900, 0200 (function name) and 7F00 again. Now, since weÃ?¢ââ??‰â??¢re inside the parenthesis, this string does have a sibling: its value. So the next chunk that weÃ?¢ââ??‰â??¢re going to write will end up having index 79E3, so our pointer looks like 0600 79E3. Now for the script table reference (not necessary, but a good practice). If you added your strings the way I told you, Ã?¢ââ??¬Ã?â??physics_set_gravityÃ?¢ââ??¬Ã? should be 6 bytes in, so type 0600 0000. And now since itÃ?¢ââ??‰â??¢s a command it doesnÃ?¢ââ??‰â??¢t have a value. HereÃ?¢ââ??‰â??¢s this chunk:78E3 7F00 0200 0900 0600 79E3 0600 0000 0000 0000 Alright, now for the value. Expression index for this chunk is 79E3. The physics_set_gravity command takes floats as its value, so that dictates our 3 types (still in reverse): 0900, 0600, and 0600. Since this is at the end of its parenthesis, it has no sibling, so add a null pointer in. ItÃ?¢ââ??‰â??¢s a value, and doesnÃ?¢ââ??‰â??¢t reference the string table (of course Bungie would still have values hereÃ?¢ââ??¬Ã?¦ go figure), so add some 0Ã?¢ââ??‰â??¢s. And now we add in the value. If you donÃ?¢ââ??‰â??¢t want 0.5 then go figure out your own value, but the hex for 0.5 (endian swapped) is 0000 003F. And thatÃ?¢ââ??‰â??¢s another chunk:79E3 0600 0600 0900 FFFF FFFF 0000 0000 0000 003F Now weÃ?¢ââ??‰â??¢ve done the bulk of our actual scripts, and are ready to do the begin statement, which we saved for last. So letÃ?¢ââ??‰â??¢s look at how that would be. WeÃ?¢ââ??‰â??¢ll start with the syntax statement. Expression index will be 7AE3. The 3 type values are: 0800, 0400, and 0000 (beginÃ?¢ââ??‰â??¢s identity). The begin expression doesnÃ?¢ââ??‰â??¢t have any siblings, so put a null sibling pointer here. Syntax expressions donÃ?¢ââ??‰â??¢t reference the table, so null pointer here. Then we need our child pointer: since the next chunk will have index 7BE3, our pointer looks like 0800 7BE3. HereÃ?¢ââ??‰â??¢s our next chunk:7AE3 0000 0400 0800 FFFF FFFF 0000 0000 0800 7BE3 And our last chunk! This will be the actual Ã?¢ââ??¬Ã?â??beginÃ?¢ââ??¬Ã?Â. So here we go. Expression index 7BE3. Types are: 0900, 0200, 0000. Now this chunk here has a sibling: the first chunk we wrote. So weÃ?¢ââ??‰â??¢re going to point it there using 0400 77E3. Now the table reference. If you made the table like I said, this will end up being 0000 0000. Since itÃ?¢ââ??‰â??¢s a command it doesnÃ?¢ââ??‰â??¢t have a value. So hereÃ?¢ââ??‰â??¢s our final chunk:7BE3 0000 0200 0900 0400 77E3 0000 0000 0000 0000. So hereÃ?¢ââ??‰â??¢s the whole thing: 77E3 7F00 0400 0800 FFFF FFFF 0000 0000 0500 78E3 78E3 7F00 0200 0900 0600 79E3 0600 0000 0000 0000 79E3 0600 0600 0900 FFFF FFFF 0000 0000 0000 003F 7AE3 0000 0400 0800 FFFF FFFF 0000 0000 0800 7BE3 7BE3 0000 0200 0900 0400 77E3 0000 0000 0000 0000 That totals 100 bytes. After the last 0000 there should be another chunk of padding (0000, followed by 18 bytes of BA). That creates the script (begin (physics_set_gravity 0.5) ) Now thereÃ?¢ââ??‰â??¢s just one thing left to do. We need to link the Ã?¢ââ??¬Ã?â??ScriptsÃ?¢ââ??¬Ã? reflexive to it, in order to put in place the Ã?¢ââ??¬Ã?â??(script startup gravity_hackÃ?¢ââ??¬Ã? and the closing Ã?¢ââ??¬Ã?â??)Ã?¢ââ??¬Ã?Â. So head on up to where you added that chunk before. You should see Ã?¢ââ??¬Ã?â??crate_eraserÃ?¢ââ??¬Ã? (if you followed my walkthrough for adding). You can go ahead and change that to whatever you want less than 32 bytes (if youÃ?¢ââ??‰â??¢re following this to the letter, that would mean gravity_hack). Now after the 32 bytes allotted for the name comes the other information. The first 2 bytes are the script type, which weÃ?¢ââ??‰â??¢re going to make startup, 0000. Then comes the return type, which will still be void (0400). Then comes the pointer into the syntax data. We want to point it to the beginning of the script, which is the Ã?¢ââ??¬Ã?â??(beginÃ?¢ââ??¬Ã? line. Its expression index is 7AE3, so our pointer looks like 0700 7AE3. Congratulations, if you managed to follow that, you should now have a low grav coagulation!! Sign the map, transfer it and enjoy. *Note* When adding scripts into a map that already has scripts, make sure you adjust the expression indices accordingly. F) Advanced StuffHere is some of the more advanced stuff. This information will be useless if you do not thoroughly understand the other concepts listed before this, so make sure you understand them first. Referencing GlobalsGlobals are variables, and can be referenced in a syntax chunk by setting the expression type to 13 (0xD), setting the identity and value type to the value type of the global, and the value to the globalÃ?¢ââ??‰â??¢s number. The first global would have a value of 0000 0000, second would have 0100 0000, third would have 0200 0000, etc. Starting Scripts from other ScriptsIn Halo2 scripts, it is possible to start a script from another script, as in the following example: (script dormat im_dormant (begin (physics_set_gravity 0.5))) (script startup im_startup (begin (wake im_dormant))) When the game starts, the game will start im_startup, and wake im_dormant, causing it to run, and set 50% gravity. Now to compile these scripts, youÃ?¢ââ??‰â??¢d need two script chunks, but youÃ?¢ââ??‰â??¢d compile it the same as other scripts, up until you get to the im_dormant part of the line (wake im_dormant). To compile the im_dormantÃ?¢ââ??‰â??¢s chunk, you give it a Value Type of 10 (0xA). To tell it what script you are waking, set the Identity to be the script number it is. In this example, the Identity would be 0, as im_dormant is the first script. So here would be the hex for this chunk: (Certain places left out with # as it can change with your situation) ExP Idnt VlTy ExTy Sibling String Value#### 0000 0A00 0900 FFFF FFFF #### #### 0000 0000 Static ScriptsThatÃ?¢ââ??‰â??¢s great and dandy, but thereÃ?¢ââ??‰â??¢s another way to do this, which will give you information back, like a command. WeÃ?¢ââ??‰â??¢re now going to call a static script: (script startup static_caller (begin (physics_set_gravity (static_script)))) (script static static_script (begin (- 0.25 0.5))) The game will start up the script static_caller, which calls the physics_set_gravity command with another script as an argument. The game then goes to static_script, evaluates it, which returns 0.75, and then the physics_set_gravity command completes with that value. It runs as if the contents of static_script are placed where it is called. With static scripts, the opening parenthesis before the name of the script is important. That is where the value type of the return type of the script is set, and the game is told its looking at a static script. The identity of the call to the static script is the script number as a short, just like when you wake a script. However, the differences are that the ( has the scriptÃ?¢ââ??‰â??¢s value type, and an Expression type of 10 (0xA). And the actual script call has an Expression Type of 9. HereÃ?¢ââ??‰â??¢s the hex for the opening parenthesis and the actual call to the script (~~~~ is expression pointer of the Ã?¢ââ??¬Ã?â??static_scriptÃ?¢ââ??¬Ã? part):ExP Idnt VlTy ExTy Sibling String Value#### 0100 0600 0A00 FFFF FFFF #### #### ~~~~ ~~~~~~~~ 0100 0200 0900 FFFF FFFF #### #### 0000 0000 Note that the first line, of the special (, can have a sibling, but in this specific script, it doesnÃ?¢ââ??‰â??¢t happen to have one. When compiling the Ã?¢ââ??¬Ã?â??static_scriptÃ?¢ââ??¬Ã? itself, just make sure to set the value type of both of the opening ( to 6, for real decimal value. When you play the game however with this script, it will simply have 0 gravity rather than -0.25% gravity. It doesnÃ?¢ââ??‰â??¢t seem Halo2 supports negative answers in subtraction, at least with real decimals. AIThe AI value type (19) can reference AI squads, whole AI platoons, or even single actors from an AI squad. To differentiate between what type you are referencing, there are different formats for the data you put in the value slot. Values:AI squad [squad#] 00 00 00AI platoon [platoon#] 00 00 40AI actor [actor#] 00 [squad#] C0 Global Variables and ConstantsHalo 2 has a few Ã?¢ââ??¬Ã?â??constantsÃ?¢ââ??¬Ã? named in the syntax as strings. Most of them are used for checking or setting the status of AI, usually in command scripts. In the command scripts, there are two constants you can use, ai_current_actor and ai_current_squad. They are both value type 19, and have expression type 13 (0xD). Value Type 7: Value:ai_combat_status_alert 2783 FFFFai_combat_status_active 2883 FFFFai_combat_status_uninspected 2983 FFFFai_combat_status_definite 2A83 FFFFai_combat_status_certain 2B83 FFFFai_combat_status_visible 2C83 FFFFai_combat_status_clear_los 2D83 FFFFai_combat_status_dangerous 2E83 FFFFai_combat_status_idle 2F83 FFFF Value Type 7:ai_movement_patrol 2F83 FFFFai_movement_combat 3183 FFFFai_movement_flee 3283 FFFF Value Type 19/31:ai_current_actor 1E83 FFFFai_current_squad 1D83 FFFF G) Credits This tutorial was written by Soldier of Light, with help by other members of Brok3n Halo, mainly Shalted, The Tycko Man, and KillingForFun. Special thanks to Doom for being the little annoying voice making me finish it >_>. If I find this tutorial posted somewhere without these credits I will personally find the person who did it and wring their neck. Thank you for reading this, and I hope you learned something from it. This tutorial has had information added to it by Agent ME. IÃ?¢ââ??‰â??¢ve added the new beginning to B) Syntax Explanation, and the F) Advanced Stuff section with information Soldier of Light and I have gathered from Halo2 scripts.
Recommended Posts
Archived
This topic is now archived and is closed to further replies.