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

GTA3asmBartonDesc
11?short integer
11&long integer
1.01.0!float (real)
$text$textglobal variable
$var18921892??global number variable
!000000@ (i think)local variable (0000 to 000f) (barton 0 to 16) or timer (0010 and 0011)
"text""text"string
%TEXTTEXTobject name
@textN/Alabel definition or reference
&textN/Amission reference



Top / Arithmetic Operations

GTA3asmBartonOperation
Boolean Negation
!NOTnegates whatever statement comes after
Equality
egi $var0000, 00000?? == 0&/0?returns true if global variable is equal to integer
egf $var0000, 0.00000?? == 0.0!returns true if global variable is equal to float
egg $var0000, $var00010000?? == 0000??returns true if global variable is equal to global variable
eli !0001, 000@ == 0&/0?returns true if local variable is equal to integer
Relational Operators
gtfg 0.0, $var00000.0! > 0000??returns true if float greater than global variable
gtgf $var0000, 0.00000?? > 0.0!returns true if global variable greater than float
gtgg $var0000, $var00010000?? > 0001??returns true if global variable greater than global variable
gtgi $var0000, 00000?? > 0&/0?returns true if global variable greater than integer
gtig 0, $var00000&/0? > 0000??returns true if integer greater than global variable
gtil 0, !00010&/0? > 00@returns true if integer greater than local variable
gtlg !0001, $var000000@ > 0000??returns true if local variable greater than global variable
gtli !0001, 000@ > 0&/0?returns true if local variable greater than integer
gtegi $var0000, 00000?? >= 0&/0?returns true if global variable greater than or equal to integer
gteig 0, $var00000&/0? >= 0000??returns true if integer greater than or equal to global variable
gteil 0, !00010&/0? >= 00@returns true if integer greater than or equal to local variable
gteli 00@, 000@ >= 0&/0?returns true if local variable greater than or equal to integer
Assignment
setgi $var0000, 00000?? = 0&/0?global variable is made equal to integer
setgf $var0000, 0.00000?? = 0.0!global variable is made equal to float
setgg $var0000, $var00010000?? = 0000??global variable is made equal to global variable
setli !0001, 000@ = 0&/0?local variable is made equal to integer
Addition
addgf $var0000, 0.00000?? += 0.0!increments global variable by float
addgg $var0000, $var00010000?? += 0000??increments global variable by global variable
addgi $var0000, 00000?? += 0&/0?increments global variable by integer
Subtraction
subgf $var0000, 0.00000?? -= 0.0!decrements global variable by float
subgg $var0000, $var00010000?? -= 0000??decrements global variable by global variable
subgi $var0000, 00000?? -= 0&/0?decrements global variable by integer
Multiplication
mulgf $var0000, 0.00000?? *= 0.0!multiply global variable by float
mulgg $var0000, $var00010000?? *= 0000??multiply global variable by global variable
mulgi $var0000, 00000?? *= 0&/0?multiply global variable by integer
Division
divgf $var0000, 0.00000?? /= 0.0!divide global variable by float
divgg $var0000, $var00010000?? /= 0000??divide global variable by global variable
divgi $var0000, 00000?? /= 0&/0?divide global variable by integer



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:

if parameterboolean operationnumber checks number trueboolean result will jf jump?
0AND1 0FY
1TN
1AND2 0FY
1FY
2TN
21OR2 0FY
1TN
2TN

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.

Car Number (Numeric Order)Car Name (Numeric Order) Car Number (Alphabetic Order)Car Name (Alphabetic Order)
90LANDSTAL140AIRTRAIN
91IDAHO106AMBULAN
92STINGER119BANSHEE
93LINERUN123BARRACKS
94PEREN132BELLYUP
95SENTINEL114BFINJECT
96PATRIOT102BLISTA
97FIRETRUK112BOBCAT
98TRASH147BORGNINE
99STRETCH121BUS
100MANANA128CABBIE
101INFERNUS105CHEETAH
102BLISTA127COACH
103PONY138COLUMB
104MULE115CORPSE
105CHEETAH141DEADDODO
106AMBULAN137DIABLOS
107FBICAR126DODO
108MOONBEAM117ENFORCER
109ESPERANT109ESPERANT
110TAXI107FBICAR
111KURUMA97FIRETRUK
112BOBCAT145FLATBED
113MRWHOOP125HELI
114BFINJECT139HOODS
115CORPSE91IDAHO
116POLICE101INFERNUS
117ENFORCER111KURUMA
118SECURICA90LANDSTAL
119BANSHEE93LINERUN
120PREDATOR134MAFIA
121BUS100MANANA
122RHINO108MOONBEAM
123BARRACKS113MRWHOOP
124TRAIN133MRWONGS
125HELI104MULE
126DODO144PANLANT
127COACH96PATRIOT
128CABBIE94PEREN
129STALLION116POLICE
130RUMPO103PONY
131RCBANDIT120PREDATOR
132BELLYUP131RCBANDIT
133MRWONGS143REEFER
134MAFIA122RHINO
135YARDIE130RUMPO
136YAKUZA118SECURICA
137DIABLOS95SENTINEL
138COLUMB142SPEEDER
139HOODS129STALLION
140AIRTRAIN92STINGER
141DEADDODO99STRETCH
142SPEEDER110TAXI
143REEFER124TRAIN
144PANLANT98TRASH
145FLATBED136YAKUZA
146YANKEE146YANKEE
147BORGNINE135YARDIE


WeaponWeapon NumberModel Number
Grenade11170
AK475171
Bat1172
Colt 452173
Molotov10174
Rocket Launcher8175
Shotgun4176
Sniper Rifle7177
Uzi3178
M166180
Flame Thrower9181
Detonator12182



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"
1