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! |