Essential Files

- Point Release
- SDK
- Q3Radiant
- MD3View

Information

- The Staff
- What's Quake3?
- What's a Mod?
- Get Hosted!

irc.telefragged.com #q3mods
News
- Current
- Archived
- Send News
Tutorials
- Coding
- Mapping
Interviews
- Caliber Mod
Mods
- Previews
:::Q3Fortress
- Reviews
Download
- Best Maps
- Best Models
- Tools
Community
- Forums
- Chat

Mod Database
- Sign-Up
- Add Mod
- Delete Mod
- View Mods
Hosted Sites
Mods

- Anarchy
- Battle Arena
- Caliber
- Chaotic Designs
- Classic Q3A
- Critical Mass
- Crusade
- Darkgift
- DarkStar
- Decimal
- Defend The Flags
- Full Metal Jacket
- Front Lines
- GatheringDarkness
- Guerilla Warfare
- Hunter
- Insanity
- Insanity Prod.
- Jagged Q3
- Nightrunner
- Obsolete
- Oblivion Demise
- Omega
- QForces
- Railfest
- ShadowRun
- SiR
- Snipers
- Team Phatass
- Terrorism
- Toons of Evil
- Tritium
- Urban Terror

Editing
- Rungy's Metropolis
- MD3Centre
- PikaMaps!
- Q3Empire
- RealGunz

 
 


Double Rockets - By Ad0

In this tutorial, I will try to learn you how to make the Rocket Launcher launch two rockets: One rocket straight forward, and another one 30 degrees downward. I will also teach you to use IF statements for controlling of the ammo. I will get into this later...

First thing to to, is to launch up the file: g_local.h. This is the main header file for the Quake 3: Arena Source.
Around line 33, you can see some flag definitions. We shall now make a flag for turning Double Rockets on and off. It's boring with non-optional gaming. At least I think. Ok, enough personal stuff, lets get to the coding! The first thing to do here, is to make a brand new flag under the
#define FL_NO_HUMANS line.
Add a code, for example like this. Toy around with the flag name, but remember that you have to use your flag name, then, in the rest of the code:

#define FL_DBLROCKET 0x00008000 //Double Rocket Flag!

What you did now, was to add a flag with another hexadecimal number (that's the 0x00008000). This is called hexadecimals. And these numbers can't be like eachother, because these are pure hexadecimals that have a special, unique "identity"! And that is not good, at least in our case. I have to mention once again: Do not paste the code. Write it off, and understand! That's the clue with these tutorials!

Allright! We have now created a flag. This flag can be used everywhere in the source now, because it's defined in the main header file, that's included in all the .c files (mostly).
The next thing to do is to make the command that's toggling this flag on and off.
Take a look at g_cmds.c, and search for "Cmd_God_f". You will now find the God Mode flag toggle function. Now we shall add a function almost like this one exept that it controls the FL_DBLROCKET flag and without the IF check for cheats. So just create a new function, named "Cmd_DblRocket_f", just above the Cmd_God_f func. If you have thought some on your own from what I wrote here, the code will look like this:

/*
=================
Cmd_DoubleRocket_f
=================
*/
void Cmd_DoubleRocket_f( gentity_t *ent ) {
      char *msg; // message to player
      ent->flags ^= FL_DBLROCKET; //Toggles our flag ON/OFF
      if (!(ent->flags & FL_DBLROCKET)) //if NOT the flag FL_DBLROCKET
          msg = "Double Rocket OFF\n";
      else
          msg = "Double Rocket ON\n";
trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg));
//sends message locally
}

OK. I really hope you got that. Comments/expainations are always after the //'s. Now we have a function for toggling the double rocket flag on and off. We made this code, just by looking and exploring Carmack's existing source code.

Now we can add this to the command list, so It can be called from the console.
Scroll down to the very end of g_cmds.c file, and crawl a bit upwards, until you find something like: else if (Q_stricmp (cmd, "god"......
It's easy to add a command: just write off the godmode console command code:
else if (Q_stricmp (cmd, "god") == 0)
          Cmd_God_f (ent);
And add a similar code, covering our function:

else if (Q_stricmp (cmd, "double") == 0) //The name of console cmd!
          Cmd_DoubleRocket_f (ent); //The exact function name!

Write this under the godmode code in the command list, and boom! There you have a full capable toggle function, aviable through the console, with command: "double".

OK! Now over to the more advanced stuff:
We shall now add a rocket, pointing 30 degrees downwards.
Open g_weapon.c and find the Weapon_RocketLauncher_Fire function.
Here is the Rocket Launcher's Launch code.

To make Quake 3: Arena understand to fire two rockets, when the FL_DBLROCKET is on. First, try to make a check code for the flag with an IF statement:

if (ent->flags & FL_DBLROCKET) {

Put this code under m->splashDamage *= s_quadFactor;.
Then you let the Rocket Launcher fire one rocket first, and then check for Double Rocket Flag.
OK. Lets continiue with the IF statement code:
Inside this IF statement you shall add a rocket with -30 degrees down. This could be done easily by copying the existing missile launch code, and add a direction expression at the top of the code:

forward[2] -= 0.2 //Almost 20-30 degrees minus
VectorNormalize( forward ); // Points the direction above
m = fire_rocket (ent, muzzle, forward); //spawns another entity
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;

Now, I am doing this the hard way, to let you know how I think when I create code. Just complain if this looks like spaghetti.
You must now make the Rocket Launcher eat two rockets instead of one.
That can be done by subtracting one more rocket from the ammo (of course). I solved this problem by looking up the name of the Rocket Launcher ammo in this source: ent->client->ps.ammo[WP_ROCKET_LAUNCHER]
then I added some easy math code somewhere INSIDE this iF statement:

ent->client->ps.ammo[WP_ROCKET_LAUNCHER] = ent->client->ps.ammo[WP_ROCKET_LAUNCHER] -1; //keep this in one line

Explaination: rocketammo = rocketammo -1 -> see?
The whole source for the IF statement in one piece (for reference):

if (ent->flags & FL_DBLROCKET) {
    ent->client->ps.ammo[WP_ROCKET_LAUNCHER] =     ent->client->ps.ammo[WP_ROCKET_LAUNCHER] -1; //keep this in one     line

    forward[2] -= 0.2 //Almost 20-30 degrees minus
    VectorNormalize( forward ); // Points the direction above
    m = fire_rocket (ent, muzzle, forward); //spawns another entity
    m->damage *= s_quadFactor;
    m->splashDamage *= s_quadFactor;
} // VERY important with a close brace after this IF statement!

OK, so that problem was solved, but as fast as I created this piece of math, another problem showed up: After taking 2 in ammo when 1 left, I suddenly got -1 in ammo, which is infinite, and that is no good!
I solved this by adding an another IF statement at the top of the entire Weapon_RocketLauncher_Fire function (under the definitions of variables (int RocketAmmo;)). I assume you have a bit knowledge about IF statements, so watch and learn:

RocketAmmo = ent->client->ps.ammo[WP_ROCKET_LAUNCHER];
if ( RocketAmmo < 1) {
m = fire_rocket (ent, muzzle, forward); //normal rocket
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;
return; //exits the function! very important, or it will still shoot two!
} //Closes the IF statement

What I just did:
At line 1 of this code, I added a "meaning" or "symonym" of the Rocket Ammo. Smart, huh?
After that I made a code that checked if I had 1 or less in ammo, and if that was true, my code inside this IF statement were executed. If the ammo was something else, the IF statement wouldn't execute, but the rest of the entire function would be executed.
Did you get that?
I will display the entire Weapon_RocketLauncher_Fire code, just for reference. Please do not copy/paste....:

void Weapon_RocketLauncher_Fire (gentity_t *ent) {
gentity_t *m;
int RocketAmmo;

RocketAmmo = ent->client->ps.ammo[WP_ROCKET_LAUNCHER];

  if ( RocketAmmo < 1) {
     m = fire_rocket (ent, muzzle, forward);
     m->damage *= s_quadFactor;
     m->splashDamage *= s_quadFactor;
     return; //exits the function (returns)
   } //Closes the IF statement

m = fire_rocket (ent, muzzle, forward); //normal rocket
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;

  if (ent->flags & FL_DBLROCKET) {
    forward[2] -= 0.2;
    ent->client->ps.ammo[WP_ROCKET_LAUNCHER] =     ent->client->ps.ammo[WP_ROCKET_LAUNCHER] -1; //keep this in one     line
    VectorNormalize( forward );
    m = fire_rocket (ent, muzzle, forward);
    m->damage *= s_quadFactor;
    m->splashDamage *= s_quadFactor;
   } //Closes the IF statement

}

I hope you understood this, really! Just send questions to my mail address above.

For my music, go here!

Cheers!