halflife-thewastes-sdk/dlls/wpn_shared/tw_melee.cpp

1312 lines
30 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