Some help with Mission Coding Table of Contents 1. Introduction 2. Basics 2.1. Tools Needed 2.2. Variable Types 3. Arithmetic Operations 4. Control Flow 4.1. Conditionals and Jumping 4.2. Subroutines 4.3. Threads 5. Car and Weapon Numbers 6. Give Weapon to Player in mission 7. Give Money to Player in mission 8. Changing Parked Cars 9. Changing Cars in missions 10. BulletProofing Cars in missions 11. Easy way to get coordinates 12. Speedometer from gta3forums.com Top / Introduction I wrote this because, well, I was bored and nothing better to do. I thought since I was just a newbie at this a few days ago I had a fair idea what's helpful. I found CyQ's tutorial very good but I personally find once you have the very basics learning from example is the easiest way from then on. This language is actually a bit foreign to me as my languages are C,Java and VB (VB is for work, I didn't want to learn it I swear!). You should read through this from start to finish, anyone who doesn't have a very basic grasp of programming/scripting should really not be doing this, those who know a resonable amount should only need to glance over the first 4 points. This has a lot of things people have said in the forums, and it is only to get you on your way. To be honest you'll learn most from reading through the code. if you want to do something the chances are it's already been done somewhere else, so check the missions and see what code did what in other missions. I could think of a lot of operations to add to this but right now this is it, I want to do more experimenting myself, but I'll post in the forum if I add more to this document. Also very important, thanks to CyQ for giving me the right numbers for weapons and telling me about using the car object names and about the wasted/busted check. Oh and for the disassembler :) Top / Basics Top / Basics / Tools Needed I started off using Barton's Mission Editor and I think it's got a lot of great features. Firstly it works directly off the main.scm file so no need for disassembling/assembling, it also has a syntax a lot easier to understand and learn with. Two fairly big drawbacks though, since it must recalculates addresses for every line added/deleted it can be very slow, also since it works directly on the main.scm file it can't use "labels", it must use addresses. Also I need to be able to comment. This editor is fantastic if you just want to search and replace car types. But for other stuff I recommend GTA3asm (dan's editor) along with vGTA3asm (a gui for the editor). I won't go into details on how to install these, you can find a link to CyG's tutorial for GTA3asm at www.game-editing.net, you can also download these tools there. Also don't worry about the disassembler, it comes inside the GTA3asm zip file Another thing to mention is that Barton also has a new Mission Builder which uses labels like GTA3asm, sounds like it's worth having a look at, got a lot of features. Find it at http://home.no.net/barton2/ I find the GXT editor very handy for finding missions, I don't know about you but I don't remember what JOEY4 was about, but 'CIPRIANI'S CHAUFFEUR' reminds me. If you look up JM4 in american.gxt you'll get the name of the mission. Top / Basics / Variable Types
Top / Arithmetic Operations
Top / Control Flow Top / Control Flow / Conditionals and Jumping Most programmers are used to the following conditionals: if, else, for, while, do...while But this script uses "labels" and jumping, think of this webpage, the links at the top move you to different areas of the page depending on where you want to go, well the code has "labels" very like a webpage's anchor which can be "jumped" to. I will show you implementations of the above conditionals using the mission script (please note these may not be the best way to implement but most illustrative) : If/Else (C style) if (x == 5) { x++; } else { x--; } If/Else (mission script - GTA3asm) @if_start if 0 egi $x, 5 jf @if_false @if_true addgi $x, 1 jump @if_end @if_false subgi $x, 1 @if_end For Loop (C style) for (x = 0; x < 5; x++) { .... } For loop (mission script - GTA3asm) @for_init setgi $x, 0 @for_loop if 0 gtig 5, $x jf @for_end @for_contents .... addgi $x, 1 jump @for_loop @for_end While Loop (C style) while (x < 5 && x > 0) { .... } While loop (mission script - GTA3asm) @while_loop if 1 gtig 5, $x gtgi $x, 0 jf @while_end @while_contents .... jump @while_loop @while_end Do...While Loop (C style) do { .... } while (x < 5 || x > 50); Do...While loop (mission script - GTA3asm) @do_loop .... if 21 gtig 5, $x gtgi $x, 50 jf @do_end jump @do_loop @while_end Just a small note to add on about "if"'s parameter. The parameter is the number of checks you want to run minus 1. From the above "While" example you see the parameter is 1 and there are 2 checks, but if you add 20 like in the "do" example instead of being a boolean AND it becomes a boolean OR. Here's where some fun boolean algebra comes in. Here's a truth table which you might find handy:
Best not to get bogged down with this if you don't understand it, there are few occasions you'll need anything other than "if 0" and 1 check. Top / Control Flow / Subroutines So now you know how to use the "if", "jf" and "jump" statements for conditionals and jumping we'll move onto Subroutines (procedures). These are reusable blocks of code, here we introduce two new statements: "gosub" and "return" Subroutine (C style) void func1() { .... return; } void main() { func1(); } Subroutine (mission script - GTA3asm) @func1 .... return @main gosub @func1 Top / Control Flow / Threads A Thread can be very useful for the more advanced features you want to put in, put you should be aware a large number of them or some poorly coded threads can seriously slow down the game. Normally only one line of code can be run at a time, but multitasking has been around a long time, how can your computer play mp3s and surf the web at the same time? well actually it can't but because computers do things so much faster than we can it can make it appear as if they are being run at same time. Basically it will switch between programs running a block of code in one then moving to the other etc. (it can be a bit more complex than that but that's the basics). Anyway back to threads, when you start a thread you're telling the game you want this to run independantly of the main program. Take the speedometer as a good example, the speedometer needs to run all the time, you could be in the middle of a Luigi mission but you still want the speedometer to run. So you make a thread which checks every so often if your in a car and displays a speedometer to the screen. You have to remember that a computer only needs to check all this code every couple of hundred milliseconds. So to stop this thread from running too fast and hogging all the resources you must put "wait" statements in certain places to pause execution. Here is an example of a thread: @thread_start wait 250 if 0 is_player_money_less_or_equal $player_char, 999999 jf @thread_start add_to_player_money $player_char, 1000000 jump @thread_start @thread_end The above code checks every 250millisecs to see if the players money is less than 1000000 and if so it will add on more (unlimited funds), but you must also call the thread: create_thread @thread_start Also worth noting, If you want to start a thread which should finish if the player is wasted or busted: create_thread_wb @thread_start You could also check manually like this: @start_thread if 0 is_wasted_or_busted jf @continue_thread end_thread @continue_thread So where should you put thread code? If you look at the bottom of MAIN you'll notice the last command is a "jump" which means that any code you put after that won't be run unless you call it, so this is the best place to put a thread. Top / Car and Weapon Numbers Here is a list of the numbers that represent vehicles in GTA3asm, thankfully Barton's editor has a vehicle dropdown list. But if you want to use cars in GTA3asm, although the ones already there are numbers like 145, you can use Object names like %FLATBED.
Top / Give Weapon to Player in mission Open up LUIGI2 in GTA3asm, if you remember this is the mission where there was a bat outside Luigi's for you to pickup. Here are the two lines of code which do this: create_pickup 172, 3, 917.1875, -425.25, 14.5, $luigi2_bat_pickup create_arrow_above_pickup $luigi2_bat_pickup, $luigi2_bat_marker This suggests to the player to use the bat by placing it on the map and putting an arrow over it. 172 is the model no of the bat, 917 is the X coordinate, -425 is Y, 14.5 is Z and the reference to this pickup is stored in $luigi2_bat_pickup. And the arrow line is obvious. But let's say I don't want to "suggest" to the player that they should use a weapon (or I'm too lazy to go looking for coordinates). Do you remember the mission "bomb da base: part II" (FRANK3), here you are given a sniper rifle. give_player_weapon $player_char, 7, 30 set_player_armed_weapon $player_char, 7 Here you are given weapon no. 7 with 30 ammo and then made use it. So lets say we want to take out the bat from LUIGI2 and instead give the player an UZI with 100 ammo, we can replace the two lines for the pickup with: give_player_weapon $player_char, 3, 100 set_player_armed_weapon $player_char, 3 It really can't get much easier than that. Top / Give Money to Player in mission This is even easier than giving weapons. If you open TONI4 for example, at the end there is: add_to_player_money $player_char, 30000 This is a good time to note that very often the end of execution isn't near the end of the file. Anyway this command can be run at any point really to give the player money, in the case above 30000 more money. Top / Changing Parked Cars Firstly I'll cover the very easy method for changing parked cars, which is simply replacing the type, then I'll tell you how to place new positions. Open MAIN and just past half way down you'll find a whole pile of these lines: init_car -1268.438, -528.625, 10.1875, 180.0, 126, -1, -1, 0, 0, 0, 0, 10000, $dodo1 The parameter list is: X,Y,Z,ANGLE,CAR NUMBER, -1 (unknown), -1 (unknown), 0 (unknown), alarm frequency (0-100), locked frequency (0-100), 0 (unknown), monetary value, car global variable. So if you want to replace the above Dodo with a Cheetah you would change the 126 to 105 and voila! Now if this isn't enough for you and you want to add more parking spots. Firstly you'll need to find some coordinates, one way to do this is to open up the map in GTA 3 Mapper and click on spots to find coordinates. Trust me, this is messy and annoying. I heard you could use "Ultimate Trainer 3.5" to do it, so I downloaded it from trainer.gtaskins.com and you run it and start the game from it. Then when you're at a certain point you can jump out and use the "Teleport" to get coordinates. I've also heard you can use the console, but I haven't tried it. The last method I've written code for, go back to the table of contents to go to it. Anyway, after finding coordinates, oh and by the way if you put in -100 for Z it calculates it for you. Firstly you can add another init_car statement: init_car 1407, -780, -100, 90, 105, -1, -1, 0, 0, 0, 0, 10000, $mycheetah The above space is in the Portland Docks beside the Mule in the car park. It will load a cheetah and have it facing towards the road (90), if I set the angle to 270 it would face away from the road. There is no alarm and no lock on the cheetah and it is saved in the variable $mycheetah. The next step is to open EIGHT and down at the very end of the file you will find: set_car_health1 $toyz4, 101 Here you can simply add the following line: set_car_health1 $mycheetah, 101 And now your all set, pretty easy too. Top / Changing Cars in missions This is very easy too. If you open up TONI2 you'll find these lines used to load up the BELLYUP used in the mission, note these lines aren't right after each other in the code, just here for illustrative purposes: request_model 132 ...... !is_model_available 132 ...... create_car 132, 892.5, -666.0, -100.0, $toni2_triad_van set_car_z_angle2 $toni2_triad_van, 180.0 ...... release_model 132 The first line requests the model, but there is also a need to check if the model is available, to be honest I don't know why this is necessary but obviously it is (maybe it takes a while to load), anyway the code just loops continuously until it this model is available. Then the van is created, the parameters are: car no, X, Y, Z (notice the -100 above), global variable. Then you can set the car's angle with the second statement. So if you wanted to change this to an everything proof cheetah here's what you would change it to: request_model 105 ...... !is_model_available 105 ...... create_car 105, 892.5, -666.0, -100.0, $toni2_triad_van set_car_z_angle2 $toni2_triad_van, 180.0 set_car_immunities $toni2_triad_van, 1, 1, 1, 0, 1 ...... release_model 105 Obviously this would be a big mistake as it's the enemies vehicle, I suppose you could rob it after killing them. Top / BulletProofing Cars in missions If you read the last section you'll know about setting immunities during in the missions. But let's say you want to be able to bulletproof every car you get into? That would be pretty sweet wouldn't it. Here's an example of code to do this using a thread, I'm not sure if it's the best way to do it, but it works. @my_bp_start setgi $my_lastcar, 0 @my_bp_afterinit wait 500 if 0 is_player_driving $me jf @my_bp_start store_player_car_2 $player_char, $my_currcar if 0 egg $my_currcar, $my_lastcar jf @my_bp_run jump @my_bp_afterinit @my_bp_run setgg $my_lastcar, $my_currcar text_highpriority "BP", 5000, 1 set_car_immunities $my_currcar, 1, 1, 1, 0, 1 jump @my_bp_afterinit And then you could just run the thread using "create_thread" at the top of MAIN underneath the "start_mission &INTRO" statement. So let me tell you what the above does, it works off checking if the player is driving and if so then is this car the same as the one which was bulletproofed last time (you don't want this bulletproof the same car over and over) if not we bulletproof and tell the user. 1. It will first set the "lastcar" variable to 0 when it first runs as there won't be a last car. There is a generous wait as we don't need this running too often. 2. If the player isn't driving we go back to start (we must set the last car back to zero, because if we drive a kuruma and then get out and then get into another kuruma we will want the second kuruma to get bp). 3. But if we are driving we get the current car, if it is the same as the last then we start again (without wiping lastcar). 4. Otherwise we have a new car so we set the lastcar to this so it won't be bulletproofed again, we tell the user (I've put a text string in american.gxt with GXT Editor which says "Your car is now BulletProof, FireProof, ExplosionProof and DentProof!!!"), we then do the actually proofing and go back to start without wiping lastcar. Top / Easy way to get coordinates Here is some code to allow you to get the coordinates of your car in the game. Basically it is a thread that checks if you beep your horn. If you beep your car horn you will get the car's coordinates. Here is the code to put at the bottom of MAIN: @my_getcoord wait 250 if 1 is_player_pressing_horn $player_char jf @my_getcoord @my_carcoord store_player_car_2 $player_char, $mycar2 get_car_coords $mycar2, $carx, $cary, $carz mulgf $carx, 100.0 mulgf $cary, 100.0 mulgf $carz, 100.0 ftoi $carx, $carx ftoi $cary, $cary ftoi $carz, $carz text_4numbers_lowpriority "COORD", $carx, $cary, $carz, 0, 250, 1 jump @my_getcoord The "COORD" text contains: "Coordinates: X ~1~, Y ~1~, Z ~1~". You'll need to create the thread too. Since we can only send integers in a message I've multiplied all the coordinates by 100, this way you can add the decimal point in after. Top / Speedometer from gta3forums.com Some of you may have read the topic on the forum about a speedometer, some people seemed confused about how to create it. Maybe this will help: @carspeed wait 500 if 0 is_player_driving $me jf @carspeed store_player_car_2 $player_char, $mycar @incar wait 50 if 0 is_player_in_car $player_char, $mycar jf @carspeed if 0 !is_car_stopped $mycar jf @incar get_car_speed $mycar, $myspeed mulgf $myspeed, 5.0 ftoi $myspeed, $myspeed setgg $myspeed_mph, $myspeed itof $myspeed_mph, $myspeed_mph divgf $myspeed_mph, 8.0 mulgf $myspeed_mph, 5.0 ftoi $myspeed_mph, $myspeed_mph text_2numbers_lowpriority "SPEEDO", $myspeed_mph, $myspeed, 50, 1 jump @incar The only difference here is I've added in the 5x multiplier which was mentioned in the topic but not put into any code, I've also changed it to show mph/kmh. "SPEEDO" is "Speed: ~1~mph/~1~kmh" |