# menu
 
http://www.planethalflife.com/hlprogramming > tutorials > database 

news
 
current
 
submit

tutorials
 
database
  -
mp
  -
client
 
submit
 
search

forum
 
main

contact
 
email

Charging Crossbow
Created by ->ViP<- Supertramp



HalfLife's Code is BLUE
->ViP<- Supertramp's Code is RED
->ViP<- Supertramp's Commentary is GREEN


Feel free to use all that code!


[Hl]
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#include "gamerules.h"


#define CROWBAR_BODYHIT_VOLUME 128
#define CROWBAR_WALLHIT_VOLUME 512

#define CROWBAR_CHARGEINTERVAL 0.3
#define CROWBAR_CHARGE_DAMAGEPLUS 3

class CCrowbar : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 1; }
void EXPORT SwingAgain( void );
void EXPORT Smack( void );
int GetItemInfo(ItemInfo *p);

void PrimaryAttack( void );
void SecondaryAttack ( void );
void WeaponIdle ( void );
int Swing( int fFirst );
BOOL Deploy( void );
void Holster( int skiplocal = 0 );
int m_iSwing;
TraceResult m_trHit;
float m_Damagefactor;
float m_flChargeStart;
float m_flReleaseCharge;
int m_oncharge;
};
LINK_ENTITY_TO_CLASS( weapon_crowbar, CCrowbar );



enum gauss_e {
CROWBAR_IDLE = 0,
CROWBAR_DRAW,
CROWBAR_HOLSTER,
CROWBAR_ATTACK1HIT,
CROWBAR_ATTACK1MISS,
CROWBAR_ATTACK2MISS,
CROWBAR_ATTACK2HIT,
CROWBAR_ATTACK3MISS,
CROWBAR_ATTACK3HIT
};


void CCrowbar::Spawn( )
{
Precache( );
m_iId = WEAPON_CROWBAR;
SET_MODEL(ENT(pev), "models/w_crowbar.mdl");
m_iClip = -1;

FallInit();// get ready to fall down.
}


void CCrowbar::Precache( void )
{
PRECACHE_MODEL("models/v_crowbar.mdl");
PRECACHE_MODEL("models/w_crowbar.mdl");
PRECACHE_MODEL("models/p_crowbar.mdl");
PRECACHE_SOUND("weapons/cbar_hit1.wav");
PRECACHE_SOUND("weapons/cbar_hit2.wav");
PRECACHE_SOUND("weapons/cbar_hitbod1.wav");
PRECACHE_SOUND("weapons/cbar_hitbod2.wav");
PRECACHE_SOUND("weapons/cbar_hitbod3.wav");
PRECACHE_SOUND("weapons/cbar_miss1.wav");
}

int CCrowbar::GetItemInfo(ItemInfo *p)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = NULL;
p->iMaxAmmo1 = -1;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 0;
p->iPosition = 0;
p->iId = WEAPON_CROWBAR;
p->iWeight = CROWBAR_WEIGHT;
return 1;
}



BOOL CCrowbar::Deploy( )
{
return DefaultDeploy( "models/v_crowbar.mdl", "models/p_crowbar.mdl", CROWBAR_DRAW, "crowbar" );
}

void CCrowbar::Holster( int skiplocal /* = 0 */ )
{
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
SendWeaponAnim( CROWBAR_HOLSTER );
}


void FindHullIntersection( const Vector &vecSrc;, TraceResult &tr;, float *mins, float *maxs, edict_t *pEntity )
{
int i, j, k;
float distance;
float *minmaxs[2] = {mins, maxs};
TraceResult tmpTrace;
Vector vecHullEnd = tr.vecEndPos;
Vector vecEnd;

distance = 1e6f;

vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2);
UTIL_TraceLine( vecSrc, vecHullEnd, dont_ignore_monsters, pEntity, &tmpTrace; );
if ( tmpTrace.flFraction < 1.0 )
{
tr = tmpTrace;
return;
}

for ( i = 0; i < 2; i++ )
{
for ( j = 0; j < 2; j++ )
{
for ( k = 0; k < 2; k++ )
{
vecEnd.x = vecHullEnd.x + minmaxs[i][0];
vecEnd.y = vecHullEnd.y + minmaxs[j][1];
vecEnd.z = vecHullEnd.z + minmaxs[k][2];

UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, pEntity, &tmpTrace; );
if ( tmpTrace.flFraction < 1.0 )
{
float thisDistance = (tmpTrace.vecEndPos - vecSrc).Length();
if ( thisDistance < distance )
{
tr = tmpTrace;
distance = thisDistance;
}
}
}
}
}
}


void CCrowbar::PrimaryAttack()
{
m_Damagefactor = 0; //set damage-plus to 0 at primary attack

if (! Swing( 1 ))
{
SetThink( SwingAgain );
pev->nextthink = gpGlobals->time + 0.1;
}
}

void CCrowbar::SecondaryAttack()
{
if (!m_oncharge)
{
m_oncharge = 1;
m_flChargeStart = gpGlobals->time;
m_flReleaseCharge = 0;
}

m_flTimeWeaponIdle = gpGlobals->time + 0.5;
}


void CCrowbar::Smack( )
{
DecalGunshot( &m;_trHit, BULLET_PLAYER_CROWBAR );
}


void CCrowbar::SwingAgain( void )
{
Swing( 0 );
}


int CCrowbar::Swing( int fFirst )
{
int fDidHit = FALSE;

TraceResult tr;

UTIL_MakeVectors (m_pPlayer->pev->v_angle);
Vector vecSrc = m_pPlayer->GetGunPosition( );
Vector vecEnd = vecSrc + gpGlobals->v_forward * 32;

UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr; );

if ( tr.flFraction >= 1.0 )
{
UTIL_TraceHull( vecSrc, vecEnd, dont_ignore_monsters, head_hull, ENT( m_pPlayer->pev ), &tr; );
if ( tr.flFraction < 1.0 )
{
// Calculate the point of intersection of the line (or hull) and the object we hit
// This is and approximation of the "best" intersection
CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit );
if ( !pHit || pHit->IsBSPModel() )
FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, m_pPlayer->edict() );
vecEnd = tr.vecEndPos; // This is the point on the actual surface (the hull could have hit space)
}
}

if ( tr.flFraction >= 1.0 )
{
if (fFirst)
{
// miss
switch( (m_iSwing++) % 3 )
{
case 0:
SendWeaponAnim( CROWBAR_ATTACK1MISS ); break;
case 1:
SendWeaponAnim( CROWBAR_ATTACK2MISS ); break;
case 2:
SendWeaponAnim( CROWBAR_ATTACK3MISS ); break;
}
m_flNextPrimaryAttack = gpGlobals->time + 0.5;
// play wiff or swish sound
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM, 0, 94 + RANDOM_LONG(0,0xF));

// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
}
}
else
{
// hit
fDidHit = TRUE;

CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);

switch( ((m_iSwing++) % 2) + 1 )
{
case 0:
SendWeaponAnim( CROWBAR_ATTACK1HIT ); break;
case 1:
SendWeaponAnim( CROWBAR_ATTACK2HIT ); break;
case 2:
SendWeaponAnim( CROWBAR_ATTACK3HIT ); break;
}

// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );

ClearMultiDamage( );
if ( (m_flNextPrimaryAttack + 1 < gpGlobals->time) || g_pGameRules->IsMultiplayer() )
{
// first swing does full damage
pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar + m_Damagefactor , gpGlobals->v_forward, &tr;, DMG_CLUB );
}
else
{
// subsequent swings do half
pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar / 2, gpGlobals->v_forward, &tr;, DMG_CLUB );
}
ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev );

m_flNextPrimaryAttack = gpGlobals->time + 0.25;

// play thwack, smack, or dong sound
float flVol = 1.0;
int fHitWorld = TRUE;

if (pEntity)
{
if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE)
{
// play thwack or smack sound
switch( RANDOM_LONG(0,2) )
{
case 0:
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); break;
case 1:
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM); break;
case 2:
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM); break;
}
m_pPlayer->m_iWeaponVolume = CROWBAR_BODYHIT_VOLUME;
if (!pEntity->IsAlive() )
return TRUE;
else
flVol = 0.1;

fHitWorld = FALSE;
}
}

// play texture hit sound
// UNDONE: Calculate the correct point of intersection when we hit with the hull instead of the line

if (fHitWorld)
{
float fvolbar = TEXTURETYPE_PlaySound(&tr;, vecSrc, vecSrc + (vecEnd-vecSrc)*2, BULLET_PLAYER_CROWBAR);

if ( g_pGameRules->IsMultiplayer() )
{
// override the volume here, cause we don''t play texture sounds in multiplayer,
// and fvolbar is going to be 0 from the above call.

fvolbar = 1;
}

// also play crowbar strike
switch( RANDOM_LONG(0,1) )
{
case 0:
//UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "weapons/cbar_hit1.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hit1.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
break;
case 1:
//UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "weapons/cbar_hit2.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hit2.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
break;
}
}

// delay the decal a bit
m_trHit = tr;
SetThink( Smack );
pev->nextthink = gpGlobals->time + 0.2;

m_pPlayer->m_iWeaponVolume = flVol * CROWBAR_WALLHIT_VOLUME;
}
return fDidHit;
}

void CCrowbar::WeaponIdle( void )
{
if ( m_flReleaseCharge == 0 )
m_flReleaseCharge = gpGlobals->time;

if ( m_flTimeWeaponIdle > gpGlobals->time )
return;

if ( m_oncharge )
{
m_oncharge = 0;
m_Damagefactor = (m_flReleaseCharge - m_flChargeStart) / CROWBAR_CHARGEINTERVAL * CROWBAR_CHARGE_DAMAGEPLUS;
Swing ( 1 );
}
}


Okay, time to explain a bit, so you can learn something :-)

At first we''ve defined 4 new variables:
int m_oncharge
float m_flChargeStart
float m_flReleaseCharge
float m_Damagefactor

m_oncharge is used to indicate if we''re charging the crowbar at the moment

m_flChargeStart is the time we started to charge
m_flReleaseCharge is the time we ended to charge
m_Damagefactor is the amount of dammage we''re adding to the standard damage (standard is 25 i think)

Now we look at SecondaryAttack.
There we initialise the Starttime, if it has''nt been done before.
Then we say that the WeaponIdle-function will be called after 0.5 sec

In WeaponIdle we set the ReleaseCharge time, than we calculate the amount of damage to add and call the Swing function to attack.

In the Swing function we go to the TraceAttack call and add our Damagefactor to the normal damage.

You''ll notice, that the crowbar will react a bit slow. That''s to make it harder to hit witch a charged crowbar. If you wanna reduce or increase this effect, reduce or increase the m_flTimeWeaponIdle variable in SecundaryAttack