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.

531 lines
13 KiB

9 years ago
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* 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.
*
****/
#if !OEM_BUILD && !HLDEMO_BUILD
9 years ago
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#include "gamerules.h"
enum satchel_state
{
SATCHEL_IDLE = 0,
SATCHEL_READY,
SATCHEL_RELOAD
};
8 years ago
enum satchel_e
{
9 years ago
SATCHEL_IDLE1 = 0,
SATCHEL_FIDGET1,
SATCHEL_DRAW,
SATCHEL_DROP
};
8 years ago
enum satchel_radio_e
{
9 years ago
SATCHEL_RADIO_IDLE1 = 0,
SATCHEL_RADIO_FIDGET1,
SATCHEL_RADIO_DRAW,
SATCHEL_RADIO_FIRE,
SATCHEL_RADIO_HOLSTER
};
LINK_ENTITY_TO_CLASS( monster_satchel, CPipebombCharge )
9 years ago
//=========================================================
// Deactivate - do whatever it is we do to an orphaned
// satchel when we don't want it in the world anymore.
//=========================================================
void CPipebombCharge::Deactivate( void )
9 years ago
{
pev->solid = SOLID_NOT;
UTIL_Remove( this );
}
void CPipebombCharge::PipebombUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
pev->owner = m_hOwner->edict();
SetThink( &CGrenade::Detonate );
pev->nextthink = gpGlobals->time;
}
void CPipebombCharge::Spawn( void )
9 years ago
{
8 years ago
Precache();
9 years ago
// motor
pev->movetype = MOVETYPE_BOUNCE;
pev->solid = SOLID_BBOX;
SET_MODEL( ENT( pev ), "models/w_pipebomb.mdl" );
8 years ago
//UTIL_SetSize( pev, Vector( -16, -16, -4 ), Vector( 16, 16, 32 ) ); // Old box -- size of headcrab monsters/players get blocked by this
UTIL_SetSize( pev, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ) ); // Uses point-sized, and can be stepped over
9 years ago
UTIL_SetOrigin( pev, pev->origin );
SetTouch( &CPipebombCharge::PipebombSlide );
SetUse( &CPipebombCharge::PipebombUse );
SetThink( &CPipebombCharge::PipebombThink );
pev->nextthink = gpGlobals->time + 0.1f;
9 years ago
pev->gravity = 0.5f;
pev->friction = 0.5f;
9 years ago
pev->dmg = gSkillData.plrDmgSatchel;
8 years ago
// ResetSequenceInfo();
9 years ago
pev->sequence = 1;
m_flDropTime = gpGlobals->time;
9 years ago
}
void CPipebombCharge::PipebombSlide( CBaseEntity *pOther )
9 years ago
{
//entvars_t *pevOther = pOther->pev;
9 years ago
// don't hit the guy that launched this grenade
if( pOther->edict() == m_hOwner->edict() )
{
if( pev->velocity.Length2D() < 10.0f
&& m_flDropTime + 0.5f <= gpGlobals->time
&& pOther->GiveAmmo( SATCHEL_DEFAULT_GIVE, "Satchel Charge", SATCHEL_MAX_CARRY ) != -1 )
{
CBasePlayer *pPlayer = static_cast<CBasePlayer*>( pOther );
EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM );
9 years ago
UTIL_Remove( this );
CPipebomb *pPipebomb = static_cast<CPipebomb*>( pPlayer->GiveNamedPlayerItem( "weapon_pipebomb" ) );
if( pPipebomb )
pPipebomb->PipebombReload();
}
return;
}
8 years ago
// pev->avelocity = Vector( 300, 300, 300 );
pev->gravity = 0.7f;// normal gravity now
9 years ago
// HACKHACK - On ground isn't always set, so look for ground underneath
TraceResult tr;
8 years ago
UTIL_TraceLine( pev->origin, pev->origin - Vector( 0, 0, 10 ), ignore_monsters, edict(), &tr );
9 years ago
if( tr.flFraction < 1.0f )
9 years ago
{
// add a bit of static friction
pev->velocity = pev->velocity * 0.7;
9 years ago
pev->avelocity = pev->avelocity * 0.9;
// play sliding sound, volume based on velocity
}
if( !( pev->flags & FL_ONGROUND ) && pev->velocity.Length2D() > 10.0f )
9 years ago
{
// Fix for a bug in engine: when object isn't moving, but its speed isn't 0 and on ground isn't set
if( pev->origin != m_lastBounceOrigin )
BounceSound();
9 years ago
}
m_lastBounceOrigin = pev->origin;
// There is no model animation so commented this out to prevent net traffic
// StudioFrameAdvance();
9 years ago
}
void CPipebombCharge::PipebombThink( void )
9 years ago
{
// There is no model animation so commented this out to prevent net traffic
// StudioFrameAdvance();
pev->nextthink = gpGlobals->time + 0.1f;
9 years ago
if( pev->owner && m_flDropTime + 0.5f <= gpGlobals->time )
pev->owner = 0;
8 years ago
if( !IsInWorld() )
9 years ago
{
UTIL_Remove( this );
return;
}
8 years ago
if( pev->waterlevel == 3 )
9 years ago
{
pev->movetype = MOVETYPE_FLY;
pev->velocity = pev->velocity * 0.8f;
pev->avelocity = pev->avelocity * 0.9f;
9 years ago
pev->velocity.z += 8;
}
8 years ago
else if( pev->waterlevel == 0 )
9 years ago
{
pev->movetype = MOVETYPE_BOUNCE;
}
else
{
pev->velocity.z -= 8.0f;
9 years ago
}
}
void CPipebombCharge::Precache( void )
9 years ago
{
PRECACHE_SOUND( "weapons/pb_bounce1.wav" );
PRECACHE_SOUND( "weapons/pb_bounce2.wav" );
PRECACHE_SOUND( "weapons/pb_bounce3.wav" );
m_iTrail = PRECACHE_MODEL( "sprites/white.spr" );
9 years ago
}
void CPipebombCharge::BounceSound( void )
9 years ago
{
8 years ago
switch( RANDOM_LONG( 0, 2 ) )
9 years ago
{
8 years ago
case 0:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/pb_bounce1.wav", 1, ATTN_NORM );
8 years ago
break;
case 1:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/pb_bounce2.wav", 1, ATTN_NORM );
8 years ago
break;
case 2:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/pb_bounce3.wav", 1, ATTN_NORM );
8 years ago
break;
9 years ago
}
}
LINK_ENTITY_TO_CLASS( weapon_pipebomb, CPipebomb )
9 years ago
//=========================================================
// CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal
//=========================================================
int CPipebomb::AddDuplicate( CBasePlayerItem *pOriginal )
9 years ago
{
CPipebomb *pPipebomb;
9 years ago
4 years ago
#if CLIENT_DLL
8 years ago
if( bIsMultiplayer() )
9 years ago
#else
8 years ago
if( g_pGameRules->IsMultiplayer() )
9 years ago
#endif
{
pPipebomb = (CPipebomb *)pOriginal;
9 years ago
if( pPipebomb->m_chargeReady != SATCHEL_IDLE )
9 years ago
{
// player has some satchels deployed. Refuse to add more.
return FALSE;
}
}
8 years ago
return CBasePlayerWeapon::AddDuplicate( pOriginal );
9 years ago
}
//=========================================================
//=========================================================
int CPipebomb::AddToPlayer( CBasePlayer *pPlayer )
9 years ago
{
int bResult = CBasePlayerItem::AddToPlayer( pPlayer );
8 years ago
pPlayer->pev->weapons |= ( 1 << m_iId );
m_chargeReady = SATCHEL_IDLE;// this satchel charge weapon now forgets that any satchels are deployed by it.
9 years ago
8 years ago
if( bResult )
9 years ago
{
8 years ago
return AddWeapon();
9 years ago
}
return FALSE;
}
void CPipebomb::Spawn()
9 years ago
{
8 years ago
Precache();
9 years ago
m_iId = WEAPON_SATCHEL;
SET_MODEL( ENT( pev ), "models/w_pipebomb.mdl" );
9 years ago
m_iDefaultAmmo = SATCHEL_DEFAULT_GIVE;
9 years ago
FallInit();// get ready to fall down.
}
void CPipebomb::Precache( void )
9 years ago
{
PRECACHE_MODEL( "models/v_pipebomb.mdl" );
PRECACHE_MODEL( "models/v_pipebomb_watch.mdl" );
PRECACHE_MODEL( "models/w_pipebomb.mdl" );
PRECACHE_MODEL( "models/p_pipebomb.mdl" );
PRECACHE_MODEL( "models/p_pipebomb_watch.mdl" );
9 years ago
UTIL_PrecacheOther( "monster_satchel" );
}
int CPipebomb::GetItemInfo( ItemInfo *p )
9 years ago
{
8 years ago
p->pszName = STRING( pev->classname );
9 years ago
p->pszAmmo1 = "Satchel Charge";
p->iMaxAmmo1 = SATCHEL_MAX_CARRY;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 4;
p->iPosition = 0;
9 years ago
p->iFlags = ITEM_FLAG_SELECTONEMPTY | ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE;
p->iId = m_iId = WEAPON_SATCHEL;
p->iWeight = SATCHEL_WEIGHT;
return 1;
}
//=========================================================
//=========================================================
BOOL CPipebomb::IsUseable( void )
9 years ago
{
return CanDeploy();
9 years ago
}
BOOL CPipebomb::CanDeploy( void )
9 years ago
{
8 years ago
if( m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] > 0 )
9 years ago
{
// player is carrying some satchels
return TRUE;
}
if( m_chargeReady )
9 years ago
{
// player isn't carrying any satchels, but has some out
return TRUE;
}
return FALSE;
}
BOOL CPipebomb::Deploy()
9 years ago
{
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0f;
BOOL result;
9 years ago
8 years ago
if( m_chargeReady )
result = DefaultDeploy( "models/v_pipebomb_watch.mdl", "models/p_pipebomb_watch.mdl", SATCHEL_RADIO_DRAW, "hive" );
9 years ago
else
result = DefaultDeploy( "models/v_pipebomb.mdl", "models/p_pipebomb.mdl", SATCHEL_DRAW, "trip" );
9 years ago
#if WEAPONS_ANIMATION_TIMES_FIX
if ( result )
{
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0f;
}
#endif
return result;
9 years ago
}
void CPipebomb::Holster( int skiplocal /* = 0 */ )
9 years ago
{
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5f;
8 years ago
if( m_chargeReady )
9 years ago
{
SendWeaponAnim( SATCHEL_RADIO_HOLSTER );
}
else
{
SendWeaponAnim( SATCHEL_DROP );
}
EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "common/null.wav", 1.0f, ATTN_NORM );
9 years ago
if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] && m_chargeReady != SATCHEL_READY )
9 years ago
{
8 years ago
m_pPlayer->pev->weapons &= ~( 1 << WEAPON_SATCHEL );
DestroyItem();
9 years ago
}
}
void CPipebomb::PrimaryAttack()
9 years ago
{
8 years ago
switch( m_chargeReady )
9 years ago
{
case SATCHEL_IDLE:
9 years ago
{
Throw();
9 years ago
}
break;
case SATCHEL_READY:
9 years ago
{
SendWeaponAnim( SATCHEL_RADIO_FIRE );
9 years ago
edict_t *pPlayer = m_pPlayer->edict();
9 years ago
CBaseEntity *pEnt = NULL;
9 years ago
while( ( pEnt = UTIL_FindEntityInSphere( pEnt, m_pPlayer->pev->origin, 4096 ) ) != NULL )
9 years ago
{
if( FClassnameIs( pEnt->pev, "monster_satchel" ) )
9 years ago
{
CPipebombCharge *pPipebomb = (CPipebombCharge *)pEnt;
if( pPipebomb->m_hOwner->edict() == pPlayer )
{
pPipebomb->Use( m_pPlayer, m_pPlayer, USE_ON, 0 );
}
9 years ago
}
}
m_chargeReady = SATCHEL_RELOAD;
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5f;
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5f;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5f;
break;
9 years ago
}
case SATCHEL_RELOAD:
9 years ago
// we're reloading, don't allow fire
break;
}
}
void CPipebomb::SecondaryAttack( void )
9 years ago
{
if( m_chargeReady != SATCHEL_RELOAD )
9 years ago
{
8 years ago
Throw();
9 years ago
}
}
void CPipebomb::Throw( void )
9 years ago
{
8 years ago
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] )
9 years ago
{
4 years ago
#if !CLIENT_DLL
9 years ago
Vector vecSrc = m_pPlayer->pev->origin;
Vector vecThrow = gpGlobals->v_forward * 274 + m_pPlayer->pev->velocity;
CPipebombCharge *pPipebomb = (CPipebombCharge *)Create( "monster_satchel", vecSrc, g_vecZero, m_pPlayer->edict() );
pPipebomb->pev->velocity = vecThrow;
pPipebomb->pev->avelocity.y = 400;
pPipebomb->m_hOwner = m_pPlayer;
pPipebomb->pev->owner = pPipebomb->m_hOwner->edict();
9 years ago
m_pPlayer->pev->viewmodel = MAKE_STRING( "models/v_pipebomb_watch.mdl" );
m_pPlayer->pev->weaponmodel = MAKE_STRING( "models/p_pipebomb_watch.mdl" );
9 years ago
#else
LoadVModel( "models/v_pipebomb_watch.mdl", m_pPlayer );
9 years ago
#endif
SendWeaponAnim( SATCHEL_RADIO_DRAW );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
m_chargeReady = SATCHEL_READY;
9 years ago
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0f;
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5f;
9 years ago
}
}
void CPipebomb::WeaponIdle( void )
9 years ago
{
8 years ago
if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
9 years ago
return;
switch( m_chargeReady )
{
case SATCHEL_IDLE:
9 years ago
SendWeaponAnim( SATCHEL_FIDGET1 );
// use tripmine animations
strcpy( m_pPlayer->m_szAnimExtention, "trip" );
break;
case SATCHEL_READY:
9 years ago
SendWeaponAnim( SATCHEL_RADIO_FIDGET1 );
// use hivehand animations
strcpy( m_pPlayer->m_szAnimExtention, "hive" );
break;
case SATCHEL_RELOAD:
8 years ago
if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] )
9 years ago
{
m_chargeReady = 0;
RetireWeapon();
return;
}
4 years ago
#if !CLIENT_DLL
m_pPlayer->pev->viewmodel = MAKE_STRING( "models/v_pipebomb.mdl" );
m_pPlayer->pev->weaponmodel = MAKE_STRING( "models/p_pipebomb.mdl" );
9 years ago
#else
LoadVModel( "models/v_pipebomb.mdl", m_pPlayer );
9 years ago
#endif
SendWeaponAnim( SATCHEL_DRAW );
// use tripmine animations
strcpy( m_pPlayer->m_szAnimExtention, "trip" );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5f;
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5f;
m_chargeReady = SATCHEL_IDLE;
9 years ago
break;
}
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again.
}
void CPipebomb::PipebombReload()
{
int i = 0;
edict_t *pPlayer = m_pPlayer->edict();
CBaseEntity *pEntity = NULL;
while( ( pEntity = UTIL_FindEntityInSphere( pEntity, m_pPlayer->pev->origin, 4096 ) ) != NULL )
{
if( FClassnameIs( pEntity->pev, "monster_satchel" ) )
{
CPipebombCharge *pPipebomb = (CPipebombCharge *)pEntity;
if( pPipebomb->m_hOwner->edict() == pPlayer )
{
++i;
}
}
}
if( i < 2 )
{
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5f;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase();
m_chargeReady = SATCHEL_RELOAD;
}
}
9 years ago
//=========================================================
// DeactivatePipebombs - removes all pipebombs owned by
9 years ago
// the provided player. Should only be used upon death.
//
// Made this global on purpose.
//=========================================================
void DeactivatePipebombs( CBasePlayer *pOwner )
9 years ago
{
edict_t *pFind;
pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "monster_satchel" );
8 years ago
while( !FNullEnt( pFind ) )
9 years ago
{
CBaseEntity *pEnt = CBaseEntity::Instance( pFind );
CPipebombCharge *pPipebomb = (CPipebombCharge *)pEnt;
9 years ago
if( pPipebomb )
9 years ago
{
if( pPipebomb->m_hOwner->edict() == pOwner->edict() )
9 years ago
{
pPipebomb->Deactivate();
9 years ago
}
}
pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "monster_satchel" );
}
}
#endif