Welcome, Guest! Login | Register

Binding new keys. [Print this Article]
Posted by: ScoBra7
Date posted: Apr 04 2003
User Rating: N/A
Number of views: 5759
Number of comments: 0
Description: Introducing new functionality.
In this tutorial we are going to add two new “key” functionalities. The first functionality is a “Fire Mode”; this is to switch the weapon’s fire mode from fire single, rapid and automatic mode. The second functionality is a “Zoom mode”. This enables zooming for most of the weapons. Actually it can be for all but it will not make sense to do it for, say, the crowbar. I will show you how to add new key binds and how to actually do these functionalities.

So let’s dive in and start coding. Open the server side workspace (mp).
Open client.cpp and find the function void ClientCommand( edict_t *pEntity ). Go down a bit to:
 CODE  
else if (FStrEq(pcmd, "lastinv" ))
{
GetClassPtr((CBasePlayer *)pev)->SelectLastItem();
}


Now insert after the curly brace (}) the following:
 CODE  
 else if (FStrEq(pcmd, "firemode" ))
{
    GetClassPtr((CBasePlayer *)pev)->ChangeFireMode();
}
else if (FStrEq(pcmd, "zoommode" ))
{
    GetClassPtr((CBasePlayer *)pev)->ChangeZoom();
}

This function receives the client commands and processes it. The code that we inserted processes the two new commands, “firemode” and “zoommode”. As you can see each of the “else if” statements’ body calls a function in CBasePlayer.

Next find the function, void ClientPrecache( void ) and add
 CODE  
 PRECACHE_SOUND("items/airtank1.wav");
This will be used in the zoom function.
Save the file client.cpp.

Open player.h. Here we are going to define the two functions and a few others.
At the top add the following after “#define PLAYER_H”:
 CODE  
 //Fire modes
#define MODE_SINGLE     0
#define MODE_RAPID      1
#define MODE_AUTO   2
#define ZOOM_NORMAL     0
#define ZOOM_1X    20
#define ZOOM_2X    10
#define FIREMODE_CHANGE_DELAY 0.5

This defines the fire - and zoom modes that we will use. It’s just a way to make the code more readable, rather than using the numerical values 0, 1 and 2.

Next find class CBasePlayer : public CBaseMonster and add the following:
 CODE  
void ChangeFireMode(void);
void ChangeZoom(void);
void SayFireMode(unsigned int iMode);
float m_flNextFireModeTime;
void ResetZoom(void);
int m_fInZoom;

The first two function definitions are used by the calls in client.cpp. The “SayFireMode” is use to display, on the HUD, what the selected fire mode is. The member variable “m_flNextFireModeTime” is used to de-bounce the keystroke, like in PrimaryFire etc. Next, the “ResetZoom” function does just that, it resets the zoom to zero. The member variable “m_fInZoom” are used to determine if we are zoomed (TRUE) or not (FALSE). You can use a bool rather than a float, it works better with MSVC 6. Just a note, for MSVC 6 rather also use the numeric 0 (zero) than NULL, the compiler will type cast the 0 better than the NULL. Save player.h

Open player.cpp. Find TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] = and add the following after the last DEFINE_FIELD statement:
 CODE  
DEFINE_FIELD( CBasePlayer, m_flNextFireModeTime  , FIELD_TIME ),


Next, find void CBasePlayer::Spawn( void ) and add the following somewhere in the function:
 CODE  
 m_flNextFireModeTime = gpGlobals->time + FIREMODE_CHANGE_DELAY;
m_fInZoom = FALSE;

So when the player spawns the values will be set. m_flNextFireModeTime is set 0.5 seconds into the future and m_fInZoom is set to FALSE.

You can add the following anywhere, I’ve added this after DropPlayerItem function:
 CODE  

//ask current weapon to change fire mode and call say mode
void CBasePlayer::ChangeFireMode(void)
{
    if ( gpGlobals->time >= m_flNextFireModeTime)
    {
  m_flNextFireModeTime = gpGlobals->time + FIREMODE_CHANGE_DELAY;
  SayFireMode(m_pActiveItem->ChangeFireMode());
    }
}

//Display the fire mode
void CBasePlayer::SayFireMode(unsigned int iMode)
{
    if(m_iFOV == 0)
    {
  switch (iMode)
  {
    case MODE_SINGLE:
    {
    ClientPrint(this->pev, HUD_PRINTCENTER, "Single Fire",0,0,0,0);
    break;
    }
    case MODE_RAPID:
    {
    ClientPrint(this->pev, HUD_PRINTCENTER, "Rapid Fire",0,0,0,0);
    break;
    }
    case MODE_AUTO:
    {
    ClientPrint(this->pev, HUD_PRINTCENTER, "Automatic Fire",0,0,0,0);
    break;
    }
  }
    }
}


//change the zoom mode
void CBasePlayer::ChangeZoom(void)
{
    if(m_pActiveItem->CanZoom(m_iFOV))
    {
  EMIT_SOUND(ENT(pev), CHAN_BODY, "items/airtank1.wav", 0.5, ATTN_NORM);
  switch (m_iFOV)
  {
    case ZOOM_NORMAL:
    {
    m_fInZoom = TRUE;
    m_iFOV = ZOOM_1X;
    break;
    }
    case ZOOM_1X:
    {
    m_fInZoom = TRUE;
    m_iFOV = ZOOM_2X;
    break;
    }
    case ZOOM_2X:
    {
    m_fInZoom = FALSE;
    m_iFOV = ZOOM_NORMAL;
    break;
    }
  }
    }
}


//Reset the zoom.
void CBasePlayer::ResetZoom()
{
    m_fInZoom = FALSE;
    m_iFOV = ZOOM_NORMAL;
}


First, the function “ChangeFireMode” will check to see if the “global” time is larger than the time set to do the fire mode. If so, the next statement sets the fire mode time 0.5 seconds into the future. Thus the fire mode can only change after 0.5 seconds has elapsed. Next the call “SayFireMode(m_pActiveItem->ChangeFireMode());” consists of two parts. First the inner part “m_pActiveItem->ChangeFireMode()” will ask the current weapon to change it’s fire mode. We will define this later on. The return value is then fed to “SayFireMode”. A note here, it will be a good idea to check that m_pActiveItem != 0 before calling this function.

Second, the function “SayFireMode” takes an “unsigned int” as a parameter, which came from the previous function “ChangeFireMode”. What happens here is we first check to see if we are in a zoom mode. We will not display fire modes if we are zoomed. Next is a switch statement to see what we need to print on the HUD.

Third, the function “ChangeZoom”. Here we ask the current weapon if we can zoom “if(m_pActiveItem->CanZoom(m_iFOV))” we also supply the zoom factor so the weapon can store and use it if needed. Next we emit a sound, just for fun. Then a switch statement to do the next increment in the zoom.

Fourthly, the function “ResetZoom”. This just resets the zoom and is called by the weapons, that does do zooming, when reloading.

This is all for player.cpp so save it.

Next open weapons.h and find class CBasePlayerItem : public CBaseAnimating. Add the following function definitions:
 CODE  
 virtual unsigned int ChangeFireMode(void){ return -1; };  //-1 if not implemented by weapon
virtual bool CanZoom(int FOV) {return false;}; //false if not implemented by weapon

So you do not have to change all the weapons, just the ones you want.

Right, I will use the MP5 to demonstrate this. So open mp5.cpp find class CMP5 : public CBasePlayerWeapon. In the public part add this:
 CODE  
 BOOL m_fInZoom;// don't save this.
unsigned int ChangeFireMode(void);
bool CanZoom(int FOV);
void Holster( int skiplocal  = 0  );

And in the private part add this:
 CODE  
unsigned short m_usFireMode;
int m_FOV;

Add the following anywhere in the file after LINK_ENTITY_TO_CLASS( weapon_9mmAR, CMP5 ); :
 CODE  

bool CMP5::CanZoom(int FOV)
{
    if (FOV == ZOOM_2X)
    {
  m_fInZoom = FALSE;
    }
    else
    {
  m_fInZoom = TRUE;
    }

    m_FOV = FOV;
    return true;
}

void CMP5::Holster( int skiplocal /* = 0 */ )
{
    m_fInReload = FALSE;// cancel any reload in progress.

    if ( m_fInZoom )
    {
  m_pPlayer->ResetZoom();
    }
}

unsigned int CMP5::ChangeFireMode()
{  
    switch (m_usFireMode)
    {
  case MODE_SINGLE:
  {
    m_usFireMode = MODE_RAPID;
    break;
  }
  case MODE_RAPID:
  {
    m_usFireMode = MODE_AUTO;
    break;
  }
  case MODE_AUTO:
  {
    m_usFireMode = MODE_SINGLE;
    break;
  }
    }
    return m_usFireMode;
}

“CanZoom” just saves the zoom factor and return true.
“Holster” will be used to reset the zoom to zero when changing weapons.
“ChangeFireMode” is the implementation of to change the fire mode.

Next find void CMP5::PrimaryAttack() and change the following from:
 CODE  
 m_flNextPrimaryAttack = gpGlobals->time + 0.1;

to
 CODE  

if(m_usFireMode == MODE_RAPID)
{
    m_flNextPrimaryAttack = gpGlobals->time + 0.05;
}
else if(m_usFireMode == MODE_AUTO)
{
    m_flNextPrimaryAttack = gpGlobals->time + 0.025;
}
else
{
    m_flNextPrimaryAttack = gpGlobals->time + 0.1;
}

This speeds up the firing.

To make the MP5 less accurate, change the VECTOR_CONE_6DEGREES to VECTOR_CONE_15DEGREES in the FireBulletsPlayer function. Save the mp5.cpp file. That’s all for the code. So build the mp.dll

To enable the player to bind the new functions to key you have to create the following directory structure in your mod directory:
\gfx\shell
Then copy the kb_act.lst file from \valve\gfx\shell to your “shell” directory. Edit the kb_act.lst using notepad or something and add the following lines, anywhere you like:
 CODE  
 "firemode"                              "Weapon Fire Mode"
"zoommode"                              "Weapon Zoom Mode"


That’s all folks. You can e-mail me at scobra@ananzi.co.za for comments and questions. There are better ways to do this but I found that this works. You can change the MODE_SINGLE, MODE_RAPID and MODE_AUTO to values that you use to divide the time with.

Rate This Article
This article has not yet been rated.

You have to register to rate this article.
User Comments

No User Comments

You must register to post a comment. If you have already registered, you must login.

Latest Articles
3rd person View in Multiplayer
Half-Life 2 | Coding | Client Side Tutorials
How to enable it in HL2DM

By: cct | Nov 13 2006

Making a Camera
Half-Life 2 | Level Design
This camera is good for when you join a map, it gives you a view of the map before you join a team

By: slackiller | Mar 05 2006

Making a camera , Part 2
Half-Life 2 | Level Design
these cameras are working monitors that turn on when a button is pushed.

By: slackiller | Mar 04 2006

Storing weapons on ladder
Half-Life 2 | Coding | Snippets
like Raven Sheild or BF2

By: British_Bomber | Dec 24 2005

Implementation of a string lookup table
Half-Life 2 | Coding | Snippets
A string lookup table is a set of functions that is used to convert strings to pre-defined values

By: deathz0rz | Nov 13 2005


Latest Comments
knock knock
General | News
By: MIFUNE | Dec 31 2017
 
knock knock
General | News
By: omega | Dec 22 2016
 
knock knock
General | News
By: MIFUNE | Oct 10 2015
 
New HL HUD Message System
Half-Life | Coding | Shared Tutorials
By: chbrules | Dec 31 2011
 
knock knock
General | News
By: Whistler | Nov 05 2011
 
Particle Engine tutorial part 4
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 18 2010
 
Particle Engine tutorial part 2
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 11 2010
 
Particle Engine tutorial part 3
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 11 2010
 
Game Movement Series #2: Analog Jumping and Floating
Half-Life 2 | Coding | Shared Tutorials
By: mars3554 | Oct 26 2009
 
Particle Engine tutorial part 5
Half-Life | Coding | Client Side Tutorials
By: Deadpool | Aug 02 2009
 

Site Info
297 Approved Articless
8 Pending Articles
3940 Registered Members
0 People Online (4 guests)
About - Credits - Contact Us

Wavelength version: 3.0.0.9
Valid XHTML 1.0! Valid CSS!