The Place to Start


TFC Rocket Launcher 
daMaker
Intermediate


TFC Rocket Launcher

Original Code is in Yellow.
New Code is in red.
Deleted original code is in striketroughed gray.

As I learned english as third language in school, excuse some mistakes... (but the c++ which is my fifth computer language should be okay *g*)

First of all, we got to make the Clipsize a bit higher. To do this, open weapons.h and change:

line 114
//
#define ROCKET_MAX_CARRY 5
#define ROCKET_MAX_CARRY 20 //rocket launcher ammo capacity is now 20

line 132
//
#define RPG_MAX_CLIP 1
but if you want it to be soldier-style (or shotgun-style), change it to:
#define RPG_MAX_CLIP 5 //now a rocket launcher clip can hold up to 5 missles

line 150
//
#define RPG_DEFAULT_GIVE 1
#define RPG_DEFAULT_GIVE 5 //Rocket Launcher spawns with 5 missles

I think there isn't much to explain :)

Now, you'll need to change everyting as it is described here:

First of all, we'll change in line 27:
enum rpg_e {
    
RPG_IDLE = 0,
    RPG_FIDGET,
    RPG_RELOAD, // to reload
    RPG_FIRE2, // to empty
    RPG_HOLSTER1, // loaded
    RPG_DRAW1, // loaded
    RPG_HOLSTER2, // unloaded
    RPG_DRAW_UL, // unloaded
    RPG_REL_START, //reload start sequence (1000 ms)
    RPG_REL_CYCLE, //reload main sequence (1500 ms)
    RPG_REL_END, //reload end sequence (1000 ms)

    RPG_IDLE_UL, // unloaded idle
    RPG_FIDGET_UL, // unloaded fidget
};

Now what does little thing of code do?
It's all easy. enum is some kind of list. Instead of writing
RPG_IDLE = 0;
RPG_FIDGET = 1;
RPG_FIRE2 = 2;
and so on, the compiler just replaces RPG_DRAW_UL with 6.
If you take a look at the original v_rpg.mld file, you will find out that animation 0 is named IDLE, animation 1 is named fidget etc. It's just names for the animation numbers.
Now why did we change that? It's all easy. We'll replace the old v_rpg.mdl file with the tfc variation: v_tfc_rpg.mdl which has different animations for reloading.


We need a little change in rpg.cpp

line 84
int m_cActiveRockets;// how many missiles in flight from this launcher right now?
int m_fInReload; //Are we in reload? (0 means no)

normally, m_fInReload is used in by the default functions to see if the weapon is in reload, but as we redefine it here, it's in a new class and new namespace or something so that the default functions (in weapons.h and .cpp) can't change it. or something like it :)

line 89
TYPEDESCRIPTION CRpg::m_SaveData[] =
{
DEFINE_FIELD( CRpg, m_fSpotActive, FIELD_INTEGER ),
DEFINE_FIELD( CRpg, m_cActiveRockets, FIELD_INTEGER ),
DEFINE_FIELD( CRpg, m_fInReload, FIELD_INTEGER),

};
IMPLEMENT_SAVERESTORE( CRpg, CBasePlayerWeapon );

I don't really know what this does, but it was the same in the shotgun.cpp which I stole most of the changes :)
It's propably something about saving information and sending it to client.dll or other players.

Now, there are some changes in CRpg::Reload( ) but we will do this at the end of the tutorial because all the prior changes will create the basics for the changes in CRpg:Reload( )

in function CRpg::Spawn ( )
m_fSpotActive = 1;
m_fInReload = 0; //doesn't start to reload when spawned :)
if ( g_pGameRules->IsMultiplayer() )
{
    
// more default ammo in multiplay.
     m_iDefaultAmmo = RPG_DEFAULT_GIVE * 2;
}
else {
m_iDefaultAmmo = RPG_DEFAULT_GIVE; }
//With our higher Ammo Size, you don't need to give more Ammo in multi-player

I got a good explanation for this change in WeaponIdle, so please be patient.

Done this? Change that:
in Rpg::Deploy( )
if ( m_iClip == 0 )
{
    return DefaultDeploy( "models/v_tfc_rpg.mdl", "models/p_rpg.mdl", RPG_DRAW_UL, "rpg" );
}
return DefaultDeploy( "models/v_tfc_rpg.mdl", "models/p_rpg.mdl", RPG_DRAW1, "rpg" ); }


in function CRpg::Precache
//PRECACHE_MODEL("models/v_rpg.mdl");
PRECACHE_MODEL("models/v_tfc_rpg.mdl");
Uses the tfc animation for the player view. In order to make this change really effective, extract the v_tcf_rpg.mdl file from /tfc/pak0.pak and put in YourModFolderHere/models/v_rfc_rpg.mdl.
But I don't know if Valve is alright with you using tfc stuff in your mod so ask them first. I don't want to have anything to do with possible or impossible copyright
violations...


in function CRpg::PrimaryAttack ( )
else
{
PlayEmptySound( );
Reload( ); //when you're trying to fire an empty rpg, it reloads instead
}

in function CRpg::WeaponIdle( )
if (m_flTimeWeaponIdle > gpGlobals->time)
return;

if (m_fInReload || !m_iClip) { Reload( ); return; } //reloads automatically if empty
Well in fact it SHOULD reload automatically but sometimes it waits some seconds to do so. (because of if (m_flTimeWeaponIdle > gpGlobals->time) {return}; )

now normally, when you collect a missle in singleplayer, you get one. But in multiplayer, you get two. Now, with the higher Clip size 5 (AMMO_RPGCLIP_GIVE), you wouldn't want to get 10 (2*AMMO_RPGCLIP_GIVE) missles. that's too much.

in function CRpg::CRpgAmmo
if ( g_pGameRules->IsMultiplayer() )
{
// hand out more ammo per rocket in multiplayer.
iGive = AMMO_RPGCLIP_GIVE * 2;
}
else
{
iGive = AMMO_RPGCLIP_GIVE;

//With this higher Ammo Size, you don't need to give more Ammo in multi-player

}

It's about the same in the Spawn( ) function (near line 425), the only difference is the name: RPG_DEFAULT_GIVE thats why you changed that above.

Now, you could think that everything is done. But if you reload now, you see that you put one missle in the launcher and you reloaded a full clip. As this is unrealistic, we'll do a shotgun style reload now (or a tfc soldier style).
In order to do that, we got to change the Reload ( ) function. delete the function and replace it with that:
(I had to replace every tab with 4 blanks but i hope I didn't ruin your day)

void CRpg::Reload( void )
{
    if (m_flNextPrimaryAttack > gpGlobals->time)
        return;

    // check to see if we're ready to reload
    if (m_fInReload == 0)
        {
        if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == RPG_MAX_CLIP)
        {
            m_fInReload = 0;
            return;
            // don't bother with any of this if don't need to reload.
        }
        m_fInReload = 1;
        SendWeaponAnim ( RPG_REL_START );
        m_flTimeWeaponIdle = gpGlobals->time + 1;
        m_flNextPrimaryAttack = gpGlobals->time + 1;
        return;
        }
    else if (m_fInReload == 1)
        {
            m_fInReload = 3;
            // Add them to the clip
        if (m_iClip < RPG_MAX_CLIP && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]>0)
            {
            //start the Weapon model animation and wait
            SendWeaponAnim( RPG_REL_CYCLE );
                m_flTimeWeaponIdle = gpGlobals->time + 1.4;
                m_flNextPrimaryAttack = gpGlobals->time + 1.4;
                m_fInReload = 2;
            }
        }
    else if (m_fInReload == 2)
        {
        m_iClip += 1;
        m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 1;
        //wait until the launcher moved back, then start over
        m_flTimeWeaponIdle = gpGlobals->time + .1;
        m_flNextPrimaryAttack = gpGlobals->time + .1;
        //when finished with that, reload another missle
        m_fInReload = 1;
        //if the launcher is full or if there are no more (less that one) missles, let him go back, then set m_fInReload = 0
        if (m_iClip >= RPG_MAX_CLIP || m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < 1) { m_fInReload = 3; }
        }
    else if (m_fInReload == 3)
    {
        SendWeaponAnim(RPG_REL_END);
        m_flTimeWeaponIdle = gpGlobals->time + 1;
        m_flNextPrimaryAttack = gpGlobals->time + 1;
        m_fInReload = 0;
    }

}

Uh, it looks to me that this could need a little bit of explanation.
First of all, the function checks if it's called too early and stops in that case. (if (m_flNextPrimaryAttack > gpGlobals->time) return;)
Then, it checks if there already is enough ammo in the Clip or if there's no ammo left. (if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == RPG_MAX_CLIP)
)
Then, it sets m_fInReload to 1 which indicates a succesful start of the reload cycle and shows the starting animation.
When m_fInReload is 1, it checks if there still is something to reload and, in that case, it starts the animation where the yellow hand puts a new missle in the launcher.
At the moment when m_fInReload is 2, the hand just finished putting that missle in the rpg, so that we can really add it (m_iClip += 1; m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 1;
).
Now, if there still is ammo and stuff, it does it again (m_fInReload = 1) otherwise, it ends the reload and sets it to 3.
If m_fInReload is finally 3, it sends the end animation (where the launcher gets back to be ready to fire) and sucessfully ends the reloading phase signaling m_fInReload = 0;

Any questions or suggestions should be sent to me: daMaker@gmx.net