6-Shot Rockets
Created By: Dr DooMer
eMail: drdoomer@cross-bones.co.uk
Difficulty Scale: Medium


The rocket launcher is every Quaker's favorite gun, right? Well, how about adding a little twist to this otherwise boring weapon. With this tutorial I will show you how to load more than one rocket into the chamber before firing, anybody familiar with Unreal's rocket launcher with be right at home. So, grab some fresh source code and open up weapons.qc for:

STEP 1:

First of all, scroll down to "ImpulseCommands", you can find it almost at the bottom. Add this just above "self.impulse = 0":

    if (self.impulse == 50)
            LoadRocket();
All this does is allow an extra impulse command that we can use to load a rocket. Next we need to make this function, look for "W_FireRocket" (about 1/3 down from the top) and add this code below the entire function, so it sits just above the Lightning functions:

void() LoadRocket =
{
    local string        loaded;        // Used later

    if (self.ammo_rockets < 1)        // If they have 0 rockets
    {
        sprint (self, "You don't have enough rockets\n"); // Let them know
        return;        // Don't let them load another
    }
    if (self.load_rockets >= 6)        // You can always change this value
    {
        sprint (self, "You already have 6 rockets loaded\n");    // Sorry, too many loaded
        return;        // Stop them from loading another
    }
    if (self.weapon != IT_ROCKET_LAUNCHER)        // If weapon is different to rocket launcher
    {
        sprint (self, "Rocket launcher only\n");    // Oh-oh! Wrong gun!
        return;        // Don't load the rockets
    }

// Right, now we can get on with the loading code

    sound (self, CHAN_WEAPON, "weapons/lock4.wav", 1, ATTN_NORM);
    self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
    self.load_rockets = self.load_rockets + 1;        // This bit loads another rocket

    loaded = ftos (self.load_rockets);    // Float to string
    sprint (self, "You now have ");       // This bit tells the
    sprint (self, loaded);                // player how many rockets
    sprint (self, " rockets armed\n");    // he has loaded

    stuffcmd (self, "bf\n");        // Simply makes the screen flash
};
There, that function is now finished. But there's one thing we must do before we can test this out:

STEP 2:

Right, save weapons.qc and go into defs.qc - only one thing to add:

.float load_rockets;
Add this right at the very bottom. Now you can compile and test, just use impulse 50 to load extra rockets! When you've finished, go to:

STEP 3:

Open up weapons.qc again and find W_Attack. Replace the section which starts with "else if (self.weapon == IT_ROCKET_LAUNCHER)" with this:

    else if (self.weapon == IT_ROCKET_LAUNCHER)
    {
        if (self.load_rockets == 0)    // No rockets loaded
        {
            sprint (self, "No rockets loaded - loading new rocket\n");
            LoadRocket();    // Add one in for convienience
            self.attack_finished = time + 0.2;    // Stop instant re-fire
        }
        else        // Otherwise fire normally
        {
            player_rocket1();
            W_FireRocket();
            self.attack_finished = time + 0.7;
        }
    }
This function stops you from firing an empty chamber, and loads a rocket if you do have an empty chamber. You can test this if you like now if you like, or you could proceed straight to the next step:

STEP 4:

Now we actually make the rockets different! Scroll back to W_FireRocket. Once you get there, rename it to W_SpawnRocket so it looks like this:

    void() W_SpawnRocket =
Then delete this line:

    self.current_ammo = self.ammo_rockets = self.ammo_rockets - 1;
This stops us from losing rockets by firing, because we've already loaded the rockets into the chamber. Now find this section:

    makevectors (self.v_angle);
    missile.velocity = aim(self, 1000);
    missile.velocity = missile.velocity * 1000;
    missile.angles = vectoangles(missile.velocity);
And change it into:

    makevectors (self.v_angle);
    missile.velocity = aim(self, 1000);
    missile.velocity = missile.velocity*600 + v_up*(crandom()*50) + v_right*(crandom()*50);
    missile.angles = vectoangles(missile.velocity);
That long line does three things - give the missile a forward velocity of 600, and a random up and right velocity. Now we move onto:

STEP 5:

Now we make a shooting function. Just above the LoadRocket function that we made, copy this:

void() W_FireRocket =
{
    while (self.load_rockets > 0)        // Repeat until you run out of loaded rockets
    {
        self.load_rockets = self.load_rockets - 1;        // Lose a loaded rocket
        W_SpawnRocket();        // Fire a rocket
    }
};
Taa-daa! That's it! Compile and have lots of fun killing, annihilating, gibbing, destroying, maiming, etc. If you run into problems when you run out of ammo, there is one more thing you could do though:

STEP 6:

Find "W_CheckNoAmmo" and replace the entire function with this:

float() W_CheckNoAmmo =
{
    if (self.currentammo > 0)
        return TRUE;

    if ((self.weapon == IT_ROCKET_LAUNCHER) && (self.load_rockets > 0))
        return TRUE;

    if (self.weapon == IT_AXE)
        return TRUE;

    self.weapon = W_BestWeapon ();

    W_SetCurrentAmmo ();

    // drop the weapon down
    return FALSE;
};
Now, this change makes Quake chack not only for when you run out of ammo, but also if you have no rockets in your chamber. Thankyou for reading - this is my first tutorial and I hope that you can follow these instructions without problems. If you would like to e-mail me please do so at mailto:drdoomer@cross-bones.co.uk and also, if you have the time, visit my homepage at www.cross-bones.co.uk .

Dr DooMer - The Fourth Reich