Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

339 lines
7.9 KiB

/*
Copyright (c) 1999, Cold Ice Modification.
This code has been written by SlimShady ( darcuri@optonline.net )
Use, distribution, and modification of this source code and/or resulting
object code is restricted to non-commercial enhancements to products from
Valve LLC. All other use, distribution, or modification is prohibited
without written permission from Valve LLC and from the Cold Ice team.
Please if you use this code in any public form, please give us credit.
*/
#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 KNIFE_BODYHIT_VOLUME 128
#define KNIFE_WALLHIT_VOLUME 512
class CKnife : 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);
int AddToPlayer( CBasePlayer *pPlayer );
int menu_on;
void PrimaryAttack( void );
int Swing( int fFirst );
BOOL Deploy( void );
void Holster( void );
int m_iSwing;
TraceResult m_trHit;
};
LINK_ENTITY_TO_CLASS( weapon_knife, CKnife );
enum knife_e {
KNIFE_IDLE = 0,
KNIFE_IDLE1,
KNIFE_SLASH,
KNIFE_STAB,
KNIFE_DRAW,
KNIFE_HOLSTER,
};
void CKnife::Spawn( )
{
Precache( );
m_iId = WEAPON_KNIFE;
SET_MODEL(ENT(pev), "models/wmodels/w_knife.mdl");
m_iClip = -1;
FallInit();
}
void CKnife::Precache( void )
{
PRECACHE_MODEL("models/vmodels/v_knife.mdl");
PRECACHE_MODEL("models/wmodels/w_knife.mdl");
PRECACHE_MODEL("models/pmodels/p_knife.mdl");
}
int CKnife::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 = 1;
p->iId = WEAPON_KNIFE;
p->iWeight = KNIFE_WEIGHT;
return 1;
}
int CKnife::AddToPlayer( CBasePlayer *pPlayer )
{
if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) )
{
MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev );
WRITE_BYTE( m_iId );
MESSAGE_END();
return TRUE;
}
return FALSE;
}
BOOL CKnife::Deploy( )
{
return DefaultDeploy( "models/vmodels/v_knife.mdl", "models/pmodels/p_knife.mdl", KNIFE_DRAW, "crowbar" );
}
void CKnife::Holster( )
{
m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5;
SendWeaponAnim( KNIFE_HOLSTER );
}
void FindHullIntersectionKnife( 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 CKnife::PrimaryAttack()
{
if (! Swing( 1 ))
{
SetThink( &CKnife::SwingAgain );
pev->nextthink = gpGlobals->time + 0.1;
}
}
void CKnife::Smack( )
{
DecalGunshot( &m_trHit, BULLET_PLAYER_CROWBAR );
}
void CKnife::SwingAgain( void )
{
Swing( 0 );
}
int CKnife::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() )
FindHullIntersectionKnife( 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( KNIFE_SLASH ); break;
case 1:
SendWeaponAnim( KNIFE_STAB ); break;
case 2:
SendWeaponAnim( KNIFE_SLASH ); 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( KNIFE_STAB ); break;
case 1:
SendWeaponAnim( KNIFE_SLASH ); break;
case 2:
SendWeaponAnim( KNIFE_STAB ); 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.plrDmgKnife, gpGlobals->v_forward, &tr, DMG_CLUB );
}
else
{
// subsequent swings do half
pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgKnife / 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 = KNIFE_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( &CKnife::Smack );
pev->nextthink = gpGlobals->time + 0.2;
m_pPlayer->m_iWeaponVolume = flVol * KNIFE_WALLHIT_VOLUME;
}
return fDidHit;
}