forked from valve/halflife-sdk
1312 lines
No EOL
31 KiB
C++
1312 lines
No EOL
31 KiB
C++
/***
|
|
*
|
|
* Copyright (C) 2002 The Wastes Project, All Rights Reserved.
|
|
*
|
|
* This product contains software technology from Valve Software, LLC,
|
|
* Copyright © 1996-2001, Valve LLC, 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
|
|
* The Wastes Project. All other use, distribution, or modification is prohibited
|
|
* without written permission from The Wastes Project.
|
|
*
|
|
***/
|
|
#include "extdll.h"
|
|
#include "util.h"
|
|
#include "cbase.h"
|
|
#include "weapons.h"
|
|
#include "weaponinfo.h"
|
|
#include "player.h"
|
|
#include "soundent.h"
|
|
#include "thewastes.h"
|
|
#include "game.h"
|
|
#include "gamerules.h"
|
|
|
|
#ifdef CLIENT_DLL
|
|
void HUD_PlaySound(char *sound,float volume);
|
|
#endif
|
|
|
|
// Entity Linkage
|
|
LINK_ENTITY_TO_CLASS(weapon_combatknife,CCombatKnife);
|
|
LINK_ENTITY_TO_CLASS(weapon_throwingknife,CThrowingKnife);
|
|
LINK_ENTITY_TO_CLASS(weapon_baseballbat,CBaseballBat);
|
|
LINK_ENTITY_TO_CLASS(weapon_sledgehammer,CSledgeHammer);
|
|
LINK_ENTITY_TO_CLASS(weapon_spear,CSpear);
|
|
LINK_ENTITY_TO_CLASS(weapon_cattleprod,CCattleProd);
|
|
LINK_ENTITY_TO_CLASS(weapon_katana,CKatana);
|
|
|
|
// Used by throwing knives and the spears!
|
|
#ifndef CLIENT_DLL
|
|
class CThrownMelee : public CBaseMonster
|
|
{
|
|
public:
|
|
void Spawn();
|
|
void Precache();
|
|
|
|
static CThrownMelee *ThrowObject(CBasePlayer *pPlayer,Vector vecOrigin,Vector vecVelocity,float flDmg,char *pszModel,char *pszClassname);
|
|
|
|
// Thinks
|
|
void EXPORT ThrownTouch(CBaseEntity *pOther);
|
|
void EXPORT ThrownThink();
|
|
private:
|
|
CBasePlayer *m_pPlayer;
|
|
|
|
char *m_pszGiveClassname;
|
|
float m_flDieTime;
|
|
};
|
|
LINK_ENTITY_TO_CLASS(thrown_object,CThrownMelee);
|
|
#endif
|
|
|
|
/*************
|
|
Melee weapons - Generic melee code
|
|
*************/
|
|
void CMeleeWeapon::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
SET_MODEL(ENT(pev),pszGetWorldModel());
|
|
|
|
FallInit();
|
|
}
|
|
|
|
void CMeleeWeapon::Precache()
|
|
{
|
|
PRECACHE_MODEL(pszGetViewModel());
|
|
PRECACHE_MODEL(pszGetPlayerModel());
|
|
PRECACHE_MODEL(pszGetWorldModel());
|
|
}
|
|
|
|
int CMeleeWeapon::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->pszName = STRING(pev->classname);
|
|
p->iSlot = 0;
|
|
p->iPosition = iItemSlot() - 1;
|
|
p->iFlags = 0;
|
|
|
|
p->pszAmmo1 = NULL;
|
|
p->iMaxAmmo1 = -1;
|
|
p->pszAmmo2 = NULL;
|
|
p->iMaxAmmo2 = -1;
|
|
p->iMaxClip = WEAPON_NOCLIP;
|
|
|
|
return 1;
|
|
}
|
|
|
|
float CMeleeWeapon::flGetAngleDamage(float flDamage,CBaseEntity *pEntity)
|
|
{
|
|
#ifndef CLIENT_DLL
|
|
// Dont calculate if we're not against a player
|
|
if(!pEntity->IsPlayer())
|
|
return flDamage;
|
|
|
|
// We calculate if the knife stab was from behind
|
|
// if so we double the initial damage.
|
|
float flDot = DotProduct(m_pPlayer->pev->angles,pEntity->pev->angles);
|
|
|
|
// Make sure we're reasonably behind the other guy
|
|
if(flDot >= 0.707f)
|
|
flDamage *= 2;
|
|
#endif
|
|
|
|
return flDamage;
|
|
}
|
|
|
|
CBaseEntity *CMeleeWeapon::SwingWeapon( float flKickback )
|
|
{
|
|
// player "shoot" animation
|
|
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
|
|
|
#ifndef CLIENT_DLL
|
|
// Attack something
|
|
TraceResult tr;
|
|
|
|
Vector vecSrc = m_pPlayer->GetGunPosition();
|
|
Vector vecAiming = gpGlobals->v_forward;
|
|
Vector vecEnd = vecSrc + gpGlobals->v_forward * flGetRange();
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
// hit
|
|
CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);
|
|
ClearMultiDamage( );
|
|
|
|
pEntity->TraceAttack(m_pPlayer->pev, flGetTiltedDamage() , gpGlobals->v_forward, &tr, iGetDamageType() );
|
|
ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev );
|
|
|
|
int HitWorld = TRUE;
|
|
|
|
if (pEntity)
|
|
{
|
|
if ( pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE )
|
|
{
|
|
PlayHitSound();
|
|
HitWorld = FALSE;
|
|
}
|
|
|
|
// Kickback from weapon
|
|
if( pEntity->IsPlayer() )
|
|
{
|
|
float flZVel = pEntity->pev->velocity.z;
|
|
pEntity->pev->velocity = pEntity->pev->velocity + gpGlobals->v_forward * flKickback;
|
|
pEntity->pev->velocity.z = flZVel;
|
|
}
|
|
}
|
|
|
|
if(HitWorld)
|
|
{
|
|
float fvol = TEXTURETYPE_PlaySound(&tr,vecSrc,vecSrc + (vecEnd-vecSrc)*2,0);
|
|
|
|
EMIT_SOUND_DYN(ENT(m_pPlayer->pev),CHAN_ITEM,"weapons/knife_hitwall.wav",fvol,ATTN_NORM,0,98 + RANDOM_LONG(0,3));
|
|
}
|
|
|
|
return pEntity;
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
void CMeleeWeapon::PlayHitSound()
|
|
{
|
|
// play thwack or smack sound
|
|
switch( RANDOM_LONG(0,2) )
|
|
{
|
|
case 0:
|
|
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); break;
|
|
case 1:
|
|
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM); break;
|
|
case 2:
|
|
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM); break;
|
|
}
|
|
}
|
|
|
|
BOOL CMeleeWeapon::PlayEmptySound()
|
|
{
|
|
if (m_iPlayEmptySound)
|
|
{
|
|
m_iPlayEmptySound = 0;
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*************
|
|
Thrown Object base code
|
|
*************/
|
|
void CThrowingWeapon::Precache()
|
|
{
|
|
#ifndef CLIENT_DLL
|
|
UTIL_PrecacheOther("thrown_object");
|
|
#endif
|
|
}
|
|
|
|
int CThrowingWeapon::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->pszName = STRING(pev->classname);
|
|
p->iSlot = 0;
|
|
p->iPosition = iItemSlot() - 1;
|
|
p->iFlags = ITEM_FLAG_EXHAUSTIBLE;
|
|
|
|
p->pszAmmo1 = pszGetAmmoName();
|
|
p->iMaxAmmo1 = iGetMaxAmmo();
|
|
p->pszAmmo2 = NULL;
|
|
p->iMaxAmmo2 = -1;
|
|
p->iMaxClip = WEAPON_NOCLIP;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void CThrowingWeapon::AttachToPlayer(CBasePlayer *pPlayer)
|
|
{
|
|
CWasteWeapon::AttachToPlayer(pPlayer);
|
|
|
|
pPlayer->GiveAmmo(1,pszGetAmmoName(),iGetMaxAmmo());
|
|
}
|
|
|
|
int CThrowingWeapon::AddDuplicate(CBasePlayerItem *pItem)
|
|
{
|
|
CBasePlayerWeapon *pWeapon = (CBasePlayerWeapon*)pItem;
|
|
|
|
if(pWeapon != NULL)
|
|
pWeapon->m_pPlayer->GiveAmmo(1,pszGetAmmoName(),iGetMaxAmmo());
|
|
|
|
return 1; // We just wanted to add ammo
|
|
}
|
|
|
|
void CThrowingWeapon::ItemPostFrame()
|
|
{
|
|
CWasteWeapon::ItemPostFrame();
|
|
|
|
if(!(m_pPlayer->pev->button & IN_ATTACK))
|
|
if(m_flStartAttack != -1.0f && m_flNextPrimaryAttack <= UTIL_WeaponTimeBase())
|
|
ThrowObject();
|
|
}
|
|
|
|
BOOL CThrowingWeapon::CanHolster()
|
|
{
|
|
// Can only holster if not ready to attack
|
|
return (m_flStartAttack == -1.0f);
|
|
}
|
|
|
|
void CThrowingWeapon::Holster( int skiplocal )
|
|
{
|
|
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < 1 )
|
|
{
|
|
// Remove this item
|
|
m_pPlayer->pev->weapons &= ~(1<<m_iId);
|
|
SetThink(DestroyItem);
|
|
pev->nextthink = gpGlobals->time + 0.1f;
|
|
}
|
|
}
|
|
|
|
/*************
|
|
Combat Knife - Everyone's got a little rambo in them
|
|
*************/
|
|
void CCombatKnife::Spawn()
|
|
{
|
|
pev->classname = MAKE_STRING("weapon_combatknife");
|
|
|
|
m_iId = WEAPON_COMBATKNIFE;
|
|
m_bSecondaryAttack = FALSE;
|
|
|
|
CMeleeWeapon::Spawn();
|
|
}
|
|
|
|
void CCombatKnife::Precache()
|
|
{
|
|
CMeleeWeapon::Precache();
|
|
|
|
PRECACHE_SOUND("weapons/combatknife_slash1.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/combatknife.sc");
|
|
}
|
|
|
|
int CCombatKnife::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->iId = m_iId = WEAPON_COMBATKNIFE;
|
|
p->iWeight = WEIGHT_COMBATKNIFE;
|
|
|
|
return CMeleeWeapon::GetItemInfo(p);
|
|
}
|
|
|
|
float CCombatKnife::flGetTiltedDamage()
|
|
{
|
|
if(m_bSecondaryAttack)
|
|
return RANDOM_FLOAT(55,65);
|
|
else
|
|
return RANDOM_FLOAT(35,45);
|
|
}
|
|
|
|
char *CCombatKnife::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_COMBATKNIFE_1 : DEATH_COMBATKNIFE_2;
|
|
}
|
|
|
|
void CCombatKnife::PrimaryAttack()
|
|
{
|
|
SwingWeapon();
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
0.0,0.0,
|
|
1, // Primary Attack
|
|
0,0,0);
|
|
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.65f;
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9); // how long till we do this again.
|
|
}
|
|
|
|
void CCombatKnife::SecondaryAttack()
|
|
{
|
|
m_bSecondaryAttack = TRUE;
|
|
|
|
SwingWeapon();
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
0.0,0.0,
|
|
0, // Secondary Attack
|
|
0,0,0);
|
|
|
|
m_bSecondaryAttack = FALSE;
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9); // how long till we do this again.
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.15f;
|
|
}
|
|
|
|
BOOL CCombatKnife::Deploy()
|
|
{
|
|
int bRet = DefaultDeploy("models/v_combatknife.mdl","models/p_combatknife.mdl",COMBATKNIFE_DRAW,"combatknife");
|
|
if(bRet)
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9);
|
|
return bRet;
|
|
}
|
|
|
|
void CCombatKnife::WeaponIdle()
|
|
{
|
|
if(m_flTimeWeaponIdle > UTIL_WeaponTimeBase())
|
|
return;
|
|
|
|
switch(RANDOM_LONG(0,2))
|
|
{
|
|
case 0:
|
|
SendWeaponAnim(COMBATKNIFE_IDLE1,UseDecrement() ? 1 : 0);
|
|
break;
|
|
case 1:
|
|
SendWeaponAnim(COMBATKNIFE_IDLE2,UseDecrement() ? 1 : 0);
|
|
break;
|
|
case 2:
|
|
SendWeaponAnim(COMBATKNIFE_IDLE3,UseDecrement() ? 1 : 0);
|
|
break;
|
|
}
|
|
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 5, 9 ); // how long till we do this again.
|
|
ResetEmptySound();
|
|
}
|
|
|
|
/*************
|
|
Throwing Knife
|
|
*************/
|
|
void CThrowingKnife::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
pev->classname = MAKE_STRING("weapon_throwingknife");
|
|
|
|
m_iId = WEAPON_THROWINGKNIFE;
|
|
m_flStartAttack = -1.0f;
|
|
m_bJustThrown = FALSE;
|
|
|
|
SET_MODEL(ENT(pev),"models/w_throwingknife.mdl");
|
|
|
|
FallInit();
|
|
}
|
|
|
|
void CThrowingKnife::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/v_throwingknife.mdl");
|
|
PRECACHE_MODEL("models/p_throwingknife.mdl");
|
|
PRECACHE_MODEL("models/w_throwingknife.mdl");
|
|
|
|
PRECACHE_SOUND("weapons/knife_throw.wav");
|
|
|
|
CThrowingWeapon::Precache();
|
|
}
|
|
|
|
int CThrowingKnife::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->iId = WEAPON_THROWINGKNIFE;
|
|
p->iWeight = WEIGHT_THROWINGKNIFE;
|
|
|
|
return CThrowingWeapon::GetItemInfo(p);
|
|
}
|
|
|
|
float CThrowingKnife::flGetTiltedDamage()
|
|
{
|
|
return RANDOM_FLOAT(55,65);
|
|
}
|
|
|
|
char *CThrowingKnife::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_THROWINGKNIFE_1 : DEATH_THROWINGKNIFE_2;
|
|
}
|
|
|
|
void CThrowingKnife::PrimaryAttack()
|
|
{
|
|
if(m_flStartAttack != -1.0f)
|
|
return;
|
|
|
|
SendWeaponAnim(TKNIFE_GOTOTHROW,UseDecrement() ? 1 : 0);
|
|
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25f;
|
|
|
|
#ifndef CLIENT_DLL
|
|
m_flStartAttack = gpGlobals->time;
|
|
#else
|
|
m_flStartAttack = 1.0f; // Just so we dont twitch the animation
|
|
#endif
|
|
}
|
|
|
|
void CThrowingKnife::ItemPostFrame()
|
|
{
|
|
if( m_bJustThrown && m_flStartAttack == -1.0f && m_flNextPrimaryAttack <= UTIL_WeaponTimeBase() )
|
|
{
|
|
SendWeaponAnim( TKNIFE_DRAW, UseDecrement() ? 1 : 0 );
|
|
m_bJustThrown = FALSE;
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25f;
|
|
}
|
|
|
|
CThrowingWeapon::ItemPostFrame();
|
|
}
|
|
|
|
void CThrowingKnife::ThrowObject()
|
|
{
|
|
SendWeaponAnim(TKNIFE_THROW,UseDecrement() ? 1 : 0);
|
|
|
|
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
|
|
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.50f;
|
|
m_flStartAttack = -1.0f;
|
|
m_bJustThrown = TRUE;
|
|
|
|
#ifndef CLIENT_DLL
|
|
float flVelocity = min(2300,(gpGlobals->time - m_flStartAttack) * 1800);
|
|
|
|
CThrownMelee::ThrowObject(m_pPlayer,m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16,
|
|
gpGlobals->v_forward * flVelocity,
|
|
flGetTiltedDamage(),"models/w_throwingknife.mdl","weapon_throwingknife");
|
|
|
|
if(m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
|
|
{
|
|
g_pGameRules->GetNextBestWeapon(m_pPlayer,this);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CLIENT_DLL
|
|
HUD_PlaySound("weapons/knife_throw.wav",1.0f);
|
|
#endif
|
|
}
|
|
|
|
BOOL CThrowingKnife::Deploy()
|
|
{
|
|
int bRet = DefaultDeploy("models/v_throwingknife.mdl","models/p_throwingknife.mdl",TKNIFE_DRAW,"tknife");
|
|
if(bRet)
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9);
|
|
return bRet;
|
|
}
|
|
|
|
void CThrowingKnife::WeaponIdle()
|
|
{
|
|
if(m_flTimeWeaponIdle >= UTIL_WeaponTimeBase())
|
|
return;
|
|
|
|
switch(RANDOM_LONG(0,1))
|
|
{
|
|
case 0: SendWeaponAnim(TKNIFE_IDLE1,UseDecrement() ? 1 : 0); break;
|
|
case 1: SendWeaponAnim(TKNIFE_IDLE2,UseDecrement() ? 1 : 0); break;
|
|
}
|
|
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9);
|
|
ResetEmptySound();
|
|
}
|
|
|
|
/*************
|
|
Baseball bat
|
|
*************/
|
|
void CBaseballBat::Spawn()
|
|
{
|
|
pev->classname = MAKE_STRING("weapon_baseballbat");
|
|
|
|
m_iId = WEAPON_BASEBALLBAT;
|
|
|
|
CMeleeWeapon::Spawn();
|
|
}
|
|
|
|
void CBaseballBat::Precache()
|
|
{
|
|
CMeleeWeapon::Precache();
|
|
|
|
PRECACHE_SOUND("weapons/baseballbat_slash1.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/baseballbat.sc");
|
|
}
|
|
|
|
int CBaseballBat::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->iId = m_iId = WEAPON_BASEBALLBAT;
|
|
p->iWeight = WEIGHT_BASEBALLBAT;
|
|
|
|
return CMeleeWeapon::GetItemInfo(p);
|
|
}
|
|
|
|
float CBaseballBat::flGetTiltedDamage()
|
|
{
|
|
return RANDOM_FLOAT(55,65);
|
|
}
|
|
|
|
char *CBaseballBat::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_BASEBALLBAT_1 : DEATH_BASEBALLBAT_2;
|
|
}
|
|
|
|
void CBaseballBat::PrimaryAttack()
|
|
{
|
|
SwingWeapon( 250.0f );
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
0.0,0.0,
|
|
0,
|
|
0,0,0);
|
|
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.85f;
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9); // how long till we do this again.
|
|
}
|
|
|
|
BOOL CBaseballBat::Deploy()
|
|
{
|
|
int bRet = DefaultDeploy("models/v_baseballbat.mdl","models/p_baseballbat.mdl",BAT_DRAW,"baseballbat");
|
|
if(bRet)
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9);
|
|
return bRet;
|
|
}
|
|
|
|
void CBaseballBat::WeaponIdle()
|
|
{
|
|
if(m_flTimeWeaponIdle > UTIL_WeaponTimeBase())
|
|
return;
|
|
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 5, 9 ); // how long till we do this again.
|
|
ResetEmptySound();
|
|
}
|
|
|
|
/*************
|
|
Sledge Hammer
|
|
*************/
|
|
void CSledgeHammer::Spawn()
|
|
{
|
|
pev->classname = MAKE_STRING("weapon_sledgehammer");
|
|
|
|
m_iId = WEAPON_SLEDGEHAMMER;
|
|
|
|
CMeleeWeapon::Spawn();
|
|
}
|
|
|
|
void CSledgeHammer::Precache()
|
|
{
|
|
CMeleeWeapon::Precache();
|
|
|
|
PRECACHE_SOUND("weapons/sledgehammer_slash1.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/sledgehammer.sc");
|
|
}
|
|
|
|
int CSledgeHammer::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->iId = m_iId = WEAPON_SLEDGEHAMMER;
|
|
p->iWeight = WEIGHT_SLEDGEHAMMER;
|
|
|
|
return CMeleeWeapon::GetItemInfo(p);
|
|
}
|
|
|
|
float CSledgeHammer::flGetTiltedDamage()
|
|
{
|
|
return RANDOM_FLOAT(65,75);
|
|
}
|
|
|
|
char *CSledgeHammer::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_SLEDGEHAMMER_1 : DEATH_SLEDGEHAMMER_2;
|
|
}
|
|
|
|
void CSledgeHammer::PrimaryAttack()
|
|
{
|
|
SwingWeapon( 350.0f );
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
0.0,0.0,
|
|
0,
|
|
0,0,0);
|
|
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0f;
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9); // how long till we do this again.
|
|
}
|
|
|
|
BOOL CSledgeHammer::Deploy()
|
|
{
|
|
int bRet = DefaultDeploy("models/v_sledge.mdl","models/p_sledge.mdl",SLEDGE_DRAW,"sledge");
|
|
if(bRet)
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9);
|
|
return bRet;
|
|
}
|
|
|
|
void CSledgeHammer::WeaponIdle()
|
|
{
|
|
if(m_flTimeWeaponIdle > UTIL_WeaponTimeBase())
|
|
return;
|
|
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 5, 9 ); // how long till we do this again.
|
|
ResetEmptySound();
|
|
}
|
|
|
|
/*************
|
|
Katana
|
|
*************/
|
|
#define KATANA_STATE_FAST 0
|
|
#define KATANA_STATE_STRONG 1
|
|
|
|
void CKatana::Spawn()
|
|
{
|
|
pev->classname = MAKE_STRING("weapon_katana");
|
|
|
|
m_iId = WEAPON_KATANA;
|
|
m_iState = KATANA_STATE_FAST;
|
|
|
|
CMeleeWeapon::Spawn();
|
|
}
|
|
|
|
void CKatana::Precache()
|
|
{
|
|
CMeleeWeapon::Precache();
|
|
|
|
PRECACHE_SOUND("weapons/katana_slash1.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/katana.sc");
|
|
}
|
|
|
|
int CKatana::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->iId = m_iId = WEAPON_KATANA;
|
|
p->iWeight = WEIGHT_KATANA;
|
|
|
|
return CMeleeWeapon::GetItemInfo(p);
|
|
}
|
|
|
|
float CKatana::flGetTiltedDamage()
|
|
{
|
|
if(m_iState == KATANA_STATE_FAST)
|
|
return RANDOM_FLOAT(55,65);
|
|
else
|
|
return RANDOM_FLOAT(65,75);
|
|
}
|
|
|
|
void CKatana::PackWeapon(void *weapon_data)
|
|
{
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
|
|
local_data->m_iWeaponState = m_iState;
|
|
}
|
|
|
|
void CKatana::UnpackWeapon(void *weapon_data)
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
weapon_data_t *local_data = (weapon_data_t*)weapon_data;
|
|
|
|
m_iState = local_data->m_iWeaponState;
|
|
#endif
|
|
}
|
|
|
|
char *CKatana::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_KATANA_1 : DEATH_KATANA_2;
|
|
}
|
|
|
|
void CKatana::PrimaryAttack()
|
|
{
|
|
SwingWeapon();
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
0.0,0.0,
|
|
(m_iState == KATANA_STATE_FAST) ? 1 : 0,
|
|
0,0,0);
|
|
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + (m_iState == KATANA_STATE_FAST) ? 0.75f : 1.15f;
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9); // how long till we do this again.
|
|
}
|
|
|
|
void CKatana::SecondaryAttack()
|
|
{
|
|
if(m_iState == KATANA_STATE_FAST)
|
|
SendWeaponAnim(KATANA_ST2_GOTO_ST1,UseDecrement() ? 1 : 0);
|
|
else
|
|
SendWeaponAnim(KATANA_ST1_GOTO_ST2,UseDecrement() ? 1 : 0);
|
|
|
|
m_iState = !m_iState;
|
|
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.5f;
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9); // how long till we do this again.
|
|
}
|
|
|
|
BOOL CKatana::Deploy()
|
|
{
|
|
int bRet = DefaultDeploy("models/v_katana.mdl","models/p_katana.mdl",KATANA_DRAW,"katana");
|
|
if(bRet)
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9);
|
|
return bRet;
|
|
}
|
|
|
|
void CKatana::Holster(int skiplocal)
|
|
{
|
|
m_iState = KATANA_STATE_FAST;
|
|
|
|
CMeleeWeapon::Holster(skiplocal);
|
|
}
|
|
|
|
void CKatana::WeaponIdle()
|
|
{
|
|
if(m_flTimeWeaponIdle > UTIL_WeaponTimeBase())
|
|
return;
|
|
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 5, 9 ); // how long till we do this again.
|
|
ResetEmptySound();
|
|
}
|
|
|
|
float CKatana::flGetRange()
|
|
{
|
|
if(m_iState == KATANA_STATE_FAST)
|
|
return 48.0f;
|
|
else
|
|
return 54.0f;
|
|
}
|
|
|
|
/*************
|
|
Cattle Prod
|
|
*************/
|
|
void CCattleProd::Spawn()
|
|
{
|
|
pev->classname = MAKE_STRING("weapon_cattleprod");
|
|
|
|
m_iId = WEAPON_CATTLEPROD;
|
|
|
|
CMeleeWeapon::Spawn();
|
|
}
|
|
|
|
void CCattleProd::Precache()
|
|
{
|
|
CMeleeWeapon::Precache();
|
|
|
|
PRECACHE_SOUND("weapons/prod_hit.wav");
|
|
PRECACHE_SOUND("weapons/prod_hitbod.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/cattleprod.sc");
|
|
}
|
|
|
|
int CCattleProd::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->iId = m_iId = WEAPON_CATTLEPROD;
|
|
p->iWeight = WEIGHT_CATTLEPROD;
|
|
|
|
return CMeleeWeapon::GetItemInfo(p);
|
|
}
|
|
|
|
float CCattleProd::flGetTiltedDamage()
|
|
{
|
|
return RANDOM_FLOAT(30,40);
|
|
}
|
|
|
|
char *CCattleProd::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_CATTLEPROD_1 : DEATH_CATTLEPROD_2;
|
|
}
|
|
|
|
void CCattleProd::PrimaryAttack()
|
|
{
|
|
CBaseEntity *pEntity = SwingWeapon();
|
|
|
|
if(m_pPlayer->pev->waterlevel > 1)
|
|
{
|
|
// Quake 1 Lightning gun type effect if you use the prod underwater
|
|
RadiusDamage(m_pPlayer->pev->origin,pev,pev,5000,512,0,DMG_SHOCK|DMG_NEVERGIB);
|
|
}
|
|
|
|
// Slow down the victim, making him easier to hit
|
|
if(pEntity != NULL && pEntity->IsPlayer())
|
|
{
|
|
HALT_PLAYER(pEntity,15,-0.10f);
|
|
}
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
0.0,0.0,
|
|
0,
|
|
0,0,0);
|
|
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.15f;
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9); // how long till we do this again.
|
|
}
|
|
|
|
BOOL CCattleProd::Deploy()
|
|
{
|
|
int bRet = DefaultDeploy("models/v_cattleprod.mdl","models/p_cattleprod.mdl",PROD_DRAW,"cattleprod");
|
|
if(bRet)
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9);
|
|
return bRet;
|
|
}
|
|
|
|
void CCattleProd::WeaponIdle()
|
|
{
|
|
if(m_flTimeWeaponIdle > UTIL_WeaponTimeBase())
|
|
return;
|
|
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 5, 9 ); // how long till we do this again.
|
|
ResetEmptySound();
|
|
}
|
|
|
|
float CCattleProd::flGetRange()
|
|
{
|
|
return 54.0f;
|
|
}
|
|
|
|
void CCattleProd::PlayHitSound()
|
|
{
|
|
EMIT_SOUND(ENT(m_pPlayer->pev),CHAN_ITEM,"weapons/prod_hitbod.wav",1,ATTN_NORM);
|
|
}
|
|
|
|
/*************
|
|
Spear
|
|
*************/
|
|
void CSpear::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
SET_MODEL(ENT(pev),"models/w_spear.mdl");
|
|
|
|
FallInit();
|
|
|
|
pev->classname = MAKE_STRING("weapon_spear");
|
|
|
|
m_flStartAttack = -1.0f;
|
|
m_iId = WEAPON_SPEAR;
|
|
m_bJustThrown = FALSE;
|
|
}
|
|
|
|
void CSpear::Precache()
|
|
{
|
|
PRECACHE_MODEL("models/v_spear.mdl");
|
|
PRECACHE_MODEL("models/p_spear.mdl");
|
|
PRECACHE_MODEL("models/w_spear.mdl");
|
|
|
|
PRECACHE_SOUND("weapons/spear_slash1.wav");
|
|
|
|
m_usFire1 = PRECACHE_EVENT(1,"events/spear.sc");
|
|
}
|
|
|
|
int CSpear::GetItemInfo(ItemInfo *p)
|
|
{
|
|
p->iId = m_iId = WEAPON_SPEAR;
|
|
p->iWeight = WEIGHT_SPEAR;
|
|
|
|
return CThrowingWeapon::GetItemInfo(p);
|
|
}
|
|
|
|
float CSpear::flGetTiltedDamage()
|
|
{
|
|
if( m_bJustThrown )
|
|
return RANDOM_FLOAT( 80,90 );
|
|
return RANDOM_FLOAT(55,65);
|
|
}
|
|
|
|
char *CSpear::szGetDeathNoticeString()
|
|
{
|
|
return RANDOM_LONG(0,1) ? DEATH_SPEAR_1 : DEATH_SPEAR_2;
|
|
}
|
|
|
|
void CSpear::SwingWeapon()
|
|
{
|
|
// player "shoot" animation
|
|
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
|
|
|
m_bJustThrown = FALSE;
|
|
|
|
#ifndef CLIENT_DLL
|
|
// Attack something
|
|
TraceResult tr;
|
|
|
|
Vector vecSrc = m_pPlayer->GetGunPosition();
|
|
Vector vecAiming = gpGlobals->v_forward;
|
|
Vector vecEnd = vecSrc + gpGlobals->v_forward * 48.0f;
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
// hit
|
|
CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);
|
|
|
|
ClearMultiDamage( );
|
|
|
|
pEntity->TraceAttack(m_pPlayer->pev, flGetTiltedDamage() , gpGlobals->v_forward, &tr, DMG_CLUB|DMG_NEVERGIB );
|
|
ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev );
|
|
|
|
int HitWorld = 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_ITEM, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); break;
|
|
case 1:
|
|
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM); break;
|
|
case 2:
|
|
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM); break;
|
|
}
|
|
|
|
HitWorld = FALSE;
|
|
}
|
|
}
|
|
|
|
if(HitWorld)
|
|
{
|
|
float fvol = TEXTURETYPE_PlaySound(&tr,vecSrc,vecSrc + (vecEnd-vecSrc)*2,0);
|
|
|
|
EMIT_SOUND_DYN(ENT(m_pPlayer->pev),CHAN_ITEM,"weapons/knife_hitwall.wav",fvol,ATTN_NORM,0,98 + RANDOM_LONG(0,3));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CSpear::ThrowObject()
|
|
{
|
|
SendWeaponAnim(SPEAR_THROW,UseDecrement() ? 1 : 0);
|
|
|
|
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
|
|
m_bJustThrown = TRUE;
|
|
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.50f;
|
|
m_flStartAttack = -1.0f;
|
|
|
|
#ifdef CLIENT_DLL
|
|
HUD_PlaySound("weapons/spear_throw.wav",1.0f);
|
|
#endif
|
|
|
|
#ifndef CLIENT_DLL
|
|
float flVelocity = min(1500,(gpGlobals->time - m_flStartAttack) * 900);
|
|
|
|
CThrownMelee *pMelee = CThrownMelee::ThrowObject(m_pPlayer,m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16,
|
|
gpGlobals->v_forward * flVelocity,
|
|
flGetTiltedDamage(),"models/w_spear.mdl","weapon_spear");
|
|
|
|
pMelee->pev->avelocity.x = 0.0f;
|
|
pMelee->pev->gravity = 0.7f;
|
|
|
|
if(m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
|
|
{
|
|
RetireWeapon();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CSpear::PrimaryAttack()
|
|
{
|
|
if(m_flStartAttack != -1.0f)
|
|
return;
|
|
|
|
SwingWeapon();
|
|
|
|
int flags;
|
|
#if defined( CLIENT_WEAPONS )
|
|
flags = FEV_NOTHOST;
|
|
#else
|
|
flags = 0;
|
|
#endif
|
|
|
|
PLAYBACK_EVENT_FULL(flags,
|
|
m_pPlayer->edict(),
|
|
m_usFire1,
|
|
0.0,
|
|
(float*)&g_vecZero,
|
|
(float*)&g_vecZero,
|
|
0.0,0.0,
|
|
0,
|
|
0,0,0);
|
|
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.85f;
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9); // how long till we do this again.
|
|
}
|
|
|
|
void CSpear::SecondaryAttack()
|
|
{
|
|
if(m_flStartAttack != -1.0f)
|
|
return;
|
|
|
|
SendWeaponAnim(SPEAR_GOTO_THROW,UseDecrement() ? 1 : 0);
|
|
|
|
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5f;
|
|
m_flStartAttack = gpGlobals->time;
|
|
}
|
|
|
|
void CSpear::ItemPostFrame()
|
|
{
|
|
if( m_bJustThrown && m_flStartAttack == -1.0f &&
|
|
m_flNextPrimaryAttack <= UTIL_WeaponTimeBase() &&
|
|
m_flNextSecondaryAttack <= UTIL_WeaponTimeBase() )
|
|
{
|
|
SendWeaponAnim( SPEAR_DRAW, UseDecrement() ? 1 : 0 );
|
|
m_bJustThrown = FALSE;
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0f;
|
|
}
|
|
|
|
if(!(m_pPlayer->pev->button & (IN_ATTACK|IN_ATTACK2)))
|
|
if(m_flStartAttack != -1.0f && m_flNextPrimaryAttack <= UTIL_WeaponTimeBase())
|
|
ThrowObject();
|
|
|
|
CWasteWeapon::ItemPostFrame();
|
|
}
|
|
|
|
BOOL CSpear::Deploy()
|
|
{
|
|
int bRet = DefaultDeploy("models/v_spear.mdl","models/p_spear.mdl",SPEAR_DRAW,"spear");
|
|
if(bRet)
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat(m_pPlayer->random_seed,5,9);
|
|
return bRet;
|
|
}
|
|
|
|
void CSpear::WeaponIdle()
|
|
{
|
|
if(m_flTimeWeaponIdle > UTIL_WeaponTimeBase())
|
|
return;
|
|
|
|
switch(RANDOM_LONG(0,1))
|
|
{
|
|
case 0: SendWeaponAnim(SPEAR_IDLE1,UseDecrement() ? 1 : 0); break;
|
|
case 1: SendWeaponAnim(SPEAR_IDLE2,UseDecrement() ? 1 : 0); break;
|
|
}
|
|
|
|
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 5, 9 ); // how long till we do this again.
|
|
ResetEmptySound();
|
|
}
|
|
|
|
//
|
|
// Thrown Object code
|
|
//
|
|
#ifndef CLIENT_DLL
|
|
|
|
void CThrownMelee::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
pev->classname = MAKE_STRING("thrown_object");
|
|
pev->movetype = MOVETYPE_TOSS;
|
|
pev->solid = SOLID_BBOX;
|
|
|
|
UTIL_SetSize(pev,Vector(0,0,0),Vector(0,0,0));
|
|
}
|
|
|
|
void CThrownMelee::Precache()
|
|
{
|
|
PRECACHE_SOUND("weapons/knife_hitwall.wav");
|
|
PRECACHE_SOUND("weapons/knife_hitbod1.wav");
|
|
PRECACHE_SOUND("weapons/knife_hitbod2.wav");
|
|
}
|
|
|
|
CThrownMelee *CThrownMelee::ThrowObject(CBasePlayer *pPlayer,Vector vecOrigin,Vector vecVelocity,float flDmg,char *pszModel,char *pszGiveClass)
|
|
{
|
|
CThrownMelee *pRetObject = GetClassPtr((CThrownMelee*)NULL);
|
|
|
|
pRetObject->Spawn();
|
|
|
|
// aerodynamic
|
|
pRetObject->pev->gravity = 0.3f;
|
|
|
|
pRetObject->m_pPlayer = pPlayer;
|
|
UTIL_SetOrigin(pRetObject->pev,vecOrigin);
|
|
|
|
pRetObject->pev->velocity = vecVelocity;
|
|
pRetObject->pev->angles = UTIL_VecToAngles(pRetObject->pev->velocity);
|
|
pRetObject->pev->owner = ENT(pPlayer->pev);
|
|
|
|
// Tumble - OMG IM GETTING DIZZY
|
|
pRetObject->pev->avelocity.x = RANDOM_FLOAT(-1800,-2000);
|
|
|
|
pRetObject->SetTouch(ThrownTouch);
|
|
pRetObject->pev->dmg = flDmg;
|
|
|
|
SET_MODEL(ENT(pRetObject->pev),pszModel);
|
|
|
|
pRetObject->m_pszGiveClassname = pszGiveClass;
|
|
|
|
return pRetObject;
|
|
}
|
|
|
|
void CThrownMelee::ThrownTouch(CBaseEntity *pOther)
|
|
{
|
|
// If we hit another throwing knife, dont run
|
|
// touch code, or else we will levitate in air!
|
|
// Instead lets just fall to the ground
|
|
if(FClassnameIs(pOther->pev,STRING(pev->classname)))
|
|
{
|
|
SetTouch(NULL);
|
|
SetThink(ThrownThink);
|
|
|
|
pev->gravity = 1.0f;
|
|
pev->avelocity.x = 0.0f;
|
|
pev->nextthink = gpGlobals->time + 0.15f;
|
|
|
|
m_flDieTime = gpGlobals->time + 30.0f;
|
|
|
|
EMIT_SOUND(ENT(m_pPlayer->pev),CHAN_AUTO,"weapons/knife_hitwall.wav",1,ATTN_NORM);
|
|
|
|
// Sparks against the other knife
|
|
MESSAGE_BEGIN(MSG_PAS,SVC_TEMPENTITY,pev->origin);
|
|
WRITE_BYTE(TE_SPARKS);
|
|
WRITE_COORD(pev->origin.x);
|
|
WRITE_COORD(pev->origin.y);
|
|
WRITE_COORD(pev->origin.z);
|
|
MESSAGE_END();
|
|
|
|
// If the other knife has his touch function set, run it...
|
|
// This should cause an action movie style feature of knifes
|
|
// hitting each other :D If the knife is on a wall, it wont work
|
|
// since its touch function is disabled.
|
|
pOther->Touch(this);
|
|
|
|
#if 0
|
|
ClientPrint(m_pPlayer->pev,HUD_PRINTCONSOLE,"Projectile Hit another object of the same class\n");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
// do damage
|
|
pOther->TakeDamage(pev,VARS(pev->owner),pev->dmg,DMG_SLASH|DMG_NEVERGIB);
|
|
|
|
// If we hit a player add ourselves to the
|
|
// Inventory, otherwise just chill.
|
|
if(pOther->IsPlayer())
|
|
{
|
|
// Make sure if we somehow hit our owner he doesnt scream like a girl :)
|
|
if(pOther != m_pPlayer)
|
|
EMIT_SOUND(ENT(pOther->pev),CHAN_AUTO,RANDOM_LONG(0,1) ? "weapons/knife_hitbod1.wav" : "weapons/knife_hitbod2.wav",1,ATTN_NORM);
|
|
|
|
((CBasePlayer*)pOther)->GiveNamedItem(m_pszGiveClassname);
|
|
UTIL_Remove(this);
|
|
}
|
|
else
|
|
{
|
|
SetTouch(NULL);
|
|
SetThink(ThrownThink);
|
|
|
|
pev->gravity = 1.0f;
|
|
pev->nextthink = gpGlobals->time + 0.15f;
|
|
pev->avelocity.x = 0.0f;
|
|
|
|
m_flDieTime = gpGlobals->time + 30.0f;
|
|
|
|
EMIT_SOUND(ENT(pev),CHAN_AUTO,"weapons/knife_hitwall.wav",1,ATTN_NORM);
|
|
|
|
if(!FStrEq(STRING(pOther->pev->classname),"func_breakable"))
|
|
{
|
|
pev->angles = UTIL_VecToAngles(pev->velocity.Normalize());
|
|
pev->movetype = MOVETYPE_NONE;
|
|
pev->velocity = g_vecZero;
|
|
|
|
// Sparks on wall from hit location
|
|
MESSAGE_BEGIN(MSG_PAS,SVC_TEMPENTITY,pev->origin);
|
|
WRITE_BYTE(TE_SPARKS);
|
|
WRITE_COORD(pev->origin.x);
|
|
WRITE_COORD(pev->origin.y);
|
|
WRITE_COORD(pev->origin.z);
|
|
MESSAGE_END();
|
|
}
|
|
else
|
|
pev->velocity = g_vecZero;
|
|
}
|
|
}
|
|
|
|
void CThrownMelee::ThrownThink()
|
|
{
|
|
CBaseEntity *pEntity = NULL;
|
|
|
|
// See if someone is able to pick us up
|
|
while((pEntity = UTIL_FindEntityInSphere(pEntity,pev->origin,16)) != NULL)
|
|
{
|
|
if(pEntity->IsPlayer())
|
|
{
|
|
((CBasePlayer*)pEntity)->GiveNamedItem(m_pszGiveClassname);
|
|
UTIL_Remove(this);
|
|
}
|
|
}
|
|
|
|
// Think again
|
|
pev->nextthink = gpGlobals->time + 0.15f;
|
|
|
|
// We shouldnt exist anymore
|
|
if(gpGlobals->time >= m_flDieTime)
|
|
UTIL_Remove(this);
|
|
}
|
|
|
|
#endif |