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.
1060 lines
28 KiB
1060 lines
28 KiB
/*** |
|
* |
|
* 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. |
|
* |
|
****/ |
|
/* |
|
|
|
===== quake_weapons.cpp ======================================================== |
|
|
|
Quake weaponry |
|
|
|
*/ |
|
|
|
#include "extdll.h" |
|
#include "util.h" |
|
#include "cbase.h" |
|
#include "player.h" |
|
#include "weapons.h" |
|
#include "gamerules.h" |
|
#include "quake_gun.h" |
|
|
|
char gszQ_DeathType[128]; |
|
DLL_GLOBAL short g_sModelIndexNail; |
|
|
|
extern unsigned short g_usHook; |
|
extern unsigned short g_usCable; |
|
extern unsigned short g_usCarried; |
|
|
|
extern bool g_bIsThreeWave; |
|
|
|
#ifdef CLIENT_DLL |
|
#include "cl_entity.h" |
|
struct cl_entity_s *GetViewEntity( void ); |
|
extern float g_flLightTime; |
|
#endif |
|
|
|
// called by worldspawn |
|
void QuakeClassicPrecache( void ) |
|
{ |
|
// Weapon sounds |
|
PRECACHE_SOUND("weapons/ax1.wav"); |
|
PRECACHE_SOUND("player/axhit2.wav"); |
|
PRECACHE_SOUND("player/axhitbod.wav"); |
|
PRECACHE_SOUND("weapons/r_exp3.wav"); // new rocket explosion |
|
PRECACHE_SOUND("weapons/rocket1i.wav");// spike gun |
|
PRECACHE_SOUND("weapons/sgun1.wav"); |
|
PRECACHE_SOUND("weapons/lhit.wav"); |
|
PRECACHE_SOUND("weapons/guncock.wav"); // player shotgun |
|
PRECACHE_SOUND("weapons/ric1.wav"); // ricochet (used in c code) |
|
PRECACHE_SOUND("weapons/ric2.wav"); // ricochet (used in c code) |
|
PRECACHE_SOUND("weapons/ric3.wav"); // ricochet (used in c code) |
|
PRECACHE_SOUND("weapons/spike2.wav"); // super spikes |
|
PRECACHE_SOUND("weapons/tink1.wav"); // spikes tink (used in c code) |
|
PRECACHE_SOUND("weapons/grenade.wav"); // grenade launcher |
|
PRECACHE_SOUND("weapons/bounce.wav"); // grenade bounce |
|
PRECACHE_SOUND("weapons/shotgn2.wav"); // super shotgun |
|
PRECACHE_SOUND("weapons/lstart.wav"); // lightning start |
|
|
|
// Weapon models |
|
PRECACHE_MODEL("models/v_crowbar.mdl"); |
|
PRECACHE_MODEL("models/v_shot.mdl"); |
|
PRECACHE_MODEL("models/v_shot2.mdl"); |
|
PRECACHE_MODEL("models/v_nail.mdl"); |
|
PRECACHE_MODEL("models/v_nail2.mdl"); |
|
PRECACHE_MODEL("models/v_rock.mdl"); |
|
PRECACHE_MODEL("models/v_rock2.mdl"); |
|
PRECACHE_MODEL("models/v_light.mdl"); |
|
|
|
// Weapon player models |
|
PRECACHE_MODEL("models/p_crowbar.mdl"); |
|
PRECACHE_MODEL("models/p_rock2.mdl"); |
|
PRECACHE_MODEL("models/p_rock.mdl"); |
|
PRECACHE_MODEL("models/p_shot2.mdl"); |
|
PRECACHE_MODEL("models/p_nail.mdl"); |
|
PRECACHE_MODEL("models/p_nail2.mdl"); |
|
PRECACHE_MODEL("models/p_light.mdl"); |
|
PRECACHE_MODEL("models/p_shot.mdl"); |
|
|
|
|
|
// Weapon effect models |
|
PRECACHE_MODEL("models/rocket.mdl"); // rocket |
|
PRECACHE_MODEL("models/grenade.mdl"); // grenade |
|
g_sModelIndexNail = PRECACHE_MODEL("models/spike.mdl"); |
|
g_sModelIndexLaser = PRECACHE_MODEL("sprites/laserbeam.spr"); |
|
PRECACHE_MODEL("sprites/smoke.spr"); |
|
|
|
// Powerup models |
|
|
|
// Powerup sounds |
|
PRECACHE_SOUND("items/damage3.wav"); |
|
PRECACHE_SOUND("items/sight1.wav"); |
|
|
|
// Teleport sounds |
|
PRECACHE_SOUND("misc/r_tele1.wav"); |
|
PRECACHE_SOUND("misc/r_tele2.wav"); |
|
PRECACHE_SOUND("misc/r_tele3.wav"); |
|
PRECACHE_SOUND("misc/r_tele4.wav"); |
|
PRECACHE_SOUND("misc/r_tele5.wav"); |
|
|
|
// Misc |
|
PRECACHE_SOUND("weapons/lock4.wav"); |
|
PRECACHE_SOUND("weapons/pkup.wav"); |
|
PRECACHE_SOUND("items/itembk2.wav"); |
|
PRECACHE_MODEL("models/backpack.mdl"); |
|
|
|
if( g_bIsThreeWave ) |
|
PRECACHE_MODEL("models/v_grapple.mdl"); |
|
} |
|
|
|
//================================================================================================ |
|
// WEAPON SELECTION |
|
//================================================================================================ |
|
// Return the ID of the best weapon being carried by the player |
|
int CBasePlayer::W_BestWeapon() |
|
{ |
|
if (pev->waterlevel <= 1 && m_iAmmoCells >= 1 && (m_iQuakeItems & IT_LIGHTNING) ) |
|
return IT_LIGHTNING; |
|
else if(m_iAmmoNails >= 2 && (m_iQuakeItems & IT_SUPER_NAILGUN) ) |
|
return IT_SUPER_NAILGUN; |
|
else if(m_iAmmoShells >= 2 && (m_iQuakeItems & IT_SUPER_SHOTGUN) ) |
|
return IT_SUPER_SHOTGUN; |
|
else if(m_iAmmoNails >= 1 && (m_iQuakeItems & IT_NAILGUN) ) |
|
return IT_NAILGUN; |
|
else if(m_iAmmoShells >= 1 && (m_iQuakeItems & IT_SHOTGUN) ) |
|
return IT_SHOTGUN; |
|
|
|
return IT_AXE; |
|
} |
|
|
|
// Weapon setup after weapon switch |
|
void CBasePlayer::W_SetCurrentAmmo( int sendanim /* = 1 */ ) |
|
{ |
|
m_iQuakeItems &= ~(IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS); |
|
int iszViewModel = 0; |
|
const char *viewmodel = ""; |
|
int iszWeaponModel = 0; |
|
const char *szAnimExt = ""; |
|
|
|
// Find out what weapon the player's using |
|
if (m_iQuakeWeapon == IT_AXE) |
|
{ |
|
m_pCurrentAmmo = NULL; |
|
viewmodel = "models/v_crowbar.mdl"; |
|
iszViewModel = MAKE_STRING(viewmodel); |
|
szAnimExt = "crowbar"; |
|
iszWeaponModel = MAKE_STRING("models/p_crowbar.mdl"); |
|
} |
|
else if (m_iQuakeWeapon == IT_SHOTGUN) |
|
{ |
|
m_pCurrentAmmo = &m_iAmmoShells; |
|
viewmodel = "models/v_shot.mdl"; |
|
iszViewModel = MAKE_STRING(viewmodel); |
|
iszWeaponModel = MAKE_STRING("models/p_shot.mdl"); |
|
m_iQuakeItems |= IT_SHELLS; |
|
szAnimExt = "shotgun"; |
|
} |
|
else if (m_iQuakeWeapon == IT_SUPER_SHOTGUN) |
|
{ |
|
m_pCurrentAmmo = &m_iAmmoShells; |
|
viewmodel = "models/v_shot2.mdl"; |
|
iszViewModel = MAKE_STRING(viewmodel); |
|
iszWeaponModel = MAKE_STRING("models/p_shot2.mdl"); |
|
m_iQuakeItems |= IT_SHELLS; |
|
szAnimExt = "shotgun"; |
|
} |
|
else if (m_iQuakeWeapon == IT_NAILGUN) |
|
{ |
|
m_pCurrentAmmo = &m_iAmmoNails; |
|
viewmodel = "models/v_nail.mdl"; |
|
iszViewModel = MAKE_STRING(viewmodel); |
|
iszWeaponModel = MAKE_STRING("models/p_nail.mdl"); |
|
m_iQuakeItems |= IT_NAILS; |
|
szAnimExt = "mp5"; |
|
} |
|
else if (m_iQuakeWeapon == IT_SUPER_NAILGUN) |
|
{ |
|
m_pCurrentAmmo = &m_iAmmoNails; |
|
viewmodel = "models/v_nail2.mdl"; |
|
iszViewModel = MAKE_STRING(viewmodel); |
|
iszWeaponModel = MAKE_STRING("models/p_nail2.mdl"); |
|
m_iQuakeItems |= IT_NAILS; |
|
szAnimExt = "mp5"; |
|
} |
|
else if (m_iQuakeWeapon == IT_GRENADE_LAUNCHER) |
|
{ |
|
m_pCurrentAmmo = &m_iAmmoRockets; |
|
viewmodel = "models/v_rock.mdl"; |
|
iszViewModel = MAKE_STRING(viewmodel); |
|
m_iQuakeItems |= IT_ROCKETS; |
|
iszWeaponModel = MAKE_STRING("models/p_rock.mdl"); |
|
szAnimExt = "gauss"; |
|
} |
|
else if (m_iQuakeWeapon == IT_ROCKET_LAUNCHER) |
|
{ |
|
m_pCurrentAmmo = &m_iAmmoRockets; |
|
viewmodel = "models/v_rock2.mdl"; |
|
iszViewModel = MAKE_STRING(viewmodel); |
|
m_iQuakeItems |= IT_ROCKETS; |
|
iszWeaponModel = MAKE_STRING("models/p_rock2.mdl"); |
|
szAnimExt = "gauss"; |
|
} |
|
else if (m_iQuakeWeapon == IT_LIGHTNING) |
|
{ |
|
m_pCurrentAmmo = &m_iAmmoCells; |
|
viewmodel = "models/v_light.mdl"; |
|
iszViewModel = MAKE_STRING(viewmodel); |
|
iszWeaponModel = MAKE_STRING("models/p_light.mdl"); |
|
m_iQuakeItems |= IT_CELLS; |
|
szAnimExt = "gauss"; |
|
} |
|
else if( m_iQuakeWeapon == IT_EXTRA_WEAPON ) |
|
{ |
|
m_pCurrentAmmo = NULL; |
|
viewmodel = "models/v_grapple.mdl"; |
|
iszViewModel = MAKE_STRING( viewmodel ); |
|
szAnimExt = "crowbar"; |
|
} |
|
else |
|
{ |
|
m_pCurrentAmmo = NULL; |
|
} |
|
|
|
#if !defined( CLIENT_DLL ) |
|
|
|
pev->viewmodel = iszViewModel; |
|
|
|
pev->weaponmodel = iszWeaponModel; |
|
m_pszAnimExtention = szAnimExt; |
|
|
|
#else |
|
{ |
|
|
|
extern int HUD_GetModelIndex( const char *modelname ); |
|
|
|
pev->viewmodel = HUD_GetModelIndex( viewmodel ); |
|
|
|
cl_entity_t *view; |
|
view = GetViewEntity(); |
|
|
|
//Adrian - The actual "magic" is done in the |
|
//Studio drawing code. |
|
if ( m_iQuakeItems & IT_INVISIBILITY ) |
|
{ |
|
if( view ) |
|
{ |
|
view->curstate.renderfx = kRenderFxGlowShell; |
|
view->curstate.renderamt = 5; |
|
|
|
view->curstate.rendercolor.r = 125; |
|
view->curstate.rendercolor.g = 125; |
|
view->curstate.rendercolor.b = 125; |
|
} |
|
} |
|
else |
|
{ |
|
if ( m_iQuakeItems & IT_INVULNERABILITY ) |
|
{ |
|
if( view ) |
|
{ |
|
view->curstate.renderfx = kRenderFxGlowShell; |
|
view->curstate.renderamt = 15; |
|
|
|
view->curstate.rendercolor.r = 255; |
|
view->curstate.rendercolor.g = 125; |
|
view->curstate.rendercolor.b = 125; |
|
} |
|
} |
|
else if ( m_iQuakeItems & IT_QUAD ) |
|
{ |
|
if( view ) |
|
{ |
|
view->curstate.renderfx = kRenderFxGlowShell; |
|
view->curstate.renderamt = 15; |
|
|
|
view->curstate.rendercolor.r = 125; |
|
view->curstate.rendercolor.g = 125; |
|
view->curstate.rendercolor.b = 255; |
|
} |
|
} |
|
else if ( m_iQuakeItems & ( IT_INVULNERABILITY | IT_QUAD ) ) |
|
{ |
|
if( view ) |
|
{ |
|
view->curstate.renderfx = kRenderFxGlowShell; |
|
view->curstate.renderamt = 15; |
|
|
|
view->curstate.rendercolor.r = 255; |
|
view->curstate.rendercolor.g = 125; |
|
view->curstate.rendercolor.b = 255; |
|
} |
|
} |
|
else |
|
view->curstate.renderfx = kRenderFxNone; // Clear it. |
|
} |
|
} |
|
#endif |
|
} |
|
|
|
// Return TRUE if the weapon still has ammo |
|
BOOL CBasePlayer::W_CheckNoAmmo() |
|
{ |
|
if ( m_pCurrentAmmo && *m_pCurrentAmmo > 0 ) |
|
return TRUE; |
|
|
|
if ( m_iQuakeWeapon == IT_AXE ) |
|
return TRUE; |
|
|
|
if( m_iQuakeWeapon == IT_EXTRA_WEAPON ) |
|
return TRUE; |
|
|
|
if ( m_iQuakeWeapon == IT_LIGHTNING ) |
|
{ |
|
PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usLightning, 0, (float *)&pev->origin, (float *)&pev->angles, 0.0, 0.0, 0, 1, 0, 0 ); |
|
|
|
if ( m_pActiveItem ) |
|
((CQuakeGun*)m_pActiveItem)->DestroyEffect(); |
|
} |
|
|
|
m_iQuakeWeapon = W_BestWeapon(); |
|
W_SetCurrentAmmo(); |
|
return FALSE; |
|
} |
|
|
|
// Change to the specified weapon |
|
void CBasePlayer::W_ChangeWeapon( int iWeaponNumber ) |
|
{ |
|
if ( m_iQuakeWeapon == IT_LIGHTNING ) |
|
{ |
|
PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usLightning, 0, (float *)&pev->origin, (float *)&pev->angles, 0.0, 0.0, 0, 1, 0, 0 ); |
|
|
|
if ( m_pActiveItem ) |
|
((CQuakeGun*)m_pActiveItem)->DestroyEffect(); |
|
} |
|
|
|
int iWeapon = 0; |
|
BOOL bHaveAmmo = TRUE; |
|
|
|
if (iWeaponNumber == 1) |
|
{ |
|
iWeapon = IT_AXE; |
|
} |
|
else if (iWeaponNumber == 2) |
|
{ |
|
iWeapon = IT_SHOTGUN; |
|
if (m_iAmmoShells < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (iWeaponNumber == 3) |
|
{ |
|
iWeapon = IT_SUPER_SHOTGUN; |
|
if (m_iAmmoShells < 2) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (iWeaponNumber == 4) |
|
{ |
|
iWeapon = IT_NAILGUN; |
|
if (m_iAmmoNails < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (iWeaponNumber == 5) |
|
{ |
|
iWeapon = IT_SUPER_NAILGUN; |
|
if (m_iAmmoNails < 2) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (iWeaponNumber == 6) |
|
{ |
|
iWeapon = IT_GRENADE_LAUNCHER; |
|
if (m_iAmmoRockets < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (iWeaponNumber == 7) |
|
{ |
|
iWeapon = IT_ROCKET_LAUNCHER; |
|
if (m_iAmmoRockets < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (iWeaponNumber == 8) |
|
{ |
|
iWeapon = IT_LIGHTNING; |
|
|
|
if (m_iAmmoCells < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (iWeaponNumber == 9) |
|
{ |
|
iWeapon = IT_EXTRA_WEAPON; |
|
} |
|
|
|
// Have the weapon? |
|
if ( !(m_iQuakeItems & iWeapon) ) |
|
{ |
|
ClientPrint( pev, HUD_PRINTCONSOLE, "#No_Weapon" ); |
|
return; |
|
} |
|
|
|
// Have ammo for it? |
|
if ( !bHaveAmmo ) |
|
{ |
|
ClientPrint( pev, HUD_PRINTCONSOLE, "#No_Ammo" ); |
|
return; |
|
} |
|
|
|
// Set weapon, update ammo |
|
m_iQuakeWeapon = iWeapon; |
|
W_SetCurrentAmmo(); |
|
|
|
#ifdef CLIENT_DLL |
|
g_flLightTime = 0.0; |
|
#endif |
|
} |
|
|
|
// Go to the next weapon with ammo |
|
void CBasePlayer::W_CycleWeaponCommand( void ) |
|
{ |
|
while (1) |
|
{ |
|
BOOL bHaveAmmo = TRUE; |
|
|
|
if (m_iQuakeWeapon == IT_LIGHTNING) |
|
{ |
|
m_iQuakeWeapon = IT_EXTRA_WEAPON; |
|
} |
|
else if (m_iQuakeWeapon == IT_EXTRA_WEAPON) |
|
{ |
|
m_iQuakeWeapon = IT_AXE; |
|
} |
|
else if (m_iQuakeWeapon == IT_AXE) |
|
{ |
|
m_iQuakeWeapon = IT_SHOTGUN; |
|
if (m_iAmmoShells < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (m_iQuakeWeapon == IT_SHOTGUN) |
|
{ |
|
m_iQuakeWeapon = IT_SUPER_SHOTGUN; |
|
if (m_iAmmoShells < 2) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (m_iQuakeWeapon == IT_SUPER_SHOTGUN) |
|
{ |
|
m_iQuakeWeapon = IT_NAILGUN; |
|
if (m_iAmmoNails < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (m_iQuakeWeapon == IT_NAILGUN) |
|
{ |
|
m_iQuakeWeapon = IT_SUPER_NAILGUN; |
|
if (m_iAmmoNails < 2) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (m_iQuakeWeapon == IT_SUPER_NAILGUN) |
|
{ |
|
m_iQuakeWeapon = IT_GRENADE_LAUNCHER; |
|
if (m_iAmmoRockets < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (m_iQuakeWeapon == IT_GRENADE_LAUNCHER) |
|
{ |
|
m_iQuakeWeapon = IT_ROCKET_LAUNCHER; |
|
if (m_iAmmoRockets < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (m_iQuakeWeapon == IT_ROCKET_LAUNCHER) |
|
{ |
|
m_iQuakeWeapon = IT_LIGHTNING; |
|
if (m_iAmmoCells < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
|
|
if ( (m_iQuakeItems & m_iQuakeWeapon) && bHaveAmmo ) |
|
{ |
|
W_SetCurrentAmmo(); |
|
return; |
|
} |
|
} |
|
|
|
} |
|
|
|
// Go to the prev weapon with ammo |
|
void CBasePlayer::W_CycleWeaponReverseCommand() |
|
{ |
|
while (1) |
|
{ |
|
BOOL bHaveAmmo = TRUE; |
|
|
|
if (m_iQuakeWeapon == IT_EXTRA_WEAPON) |
|
{ |
|
m_iQuakeWeapon = IT_LIGHTNING; |
|
} |
|
else if (m_iQuakeWeapon == IT_LIGHTNING) |
|
{ |
|
m_iQuakeWeapon = IT_ROCKET_LAUNCHER; |
|
if (m_iAmmoRockets < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (m_iQuakeWeapon == IT_ROCKET_LAUNCHER) |
|
{ |
|
m_iQuakeWeapon = IT_GRENADE_LAUNCHER; |
|
if (m_iAmmoRockets < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (m_iQuakeWeapon == IT_GRENADE_LAUNCHER) |
|
{ |
|
m_iQuakeWeapon = IT_SUPER_NAILGUN; |
|
if (m_iAmmoNails < 2) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (m_iQuakeWeapon == IT_SUPER_NAILGUN) |
|
{ |
|
m_iQuakeWeapon = IT_NAILGUN; |
|
if (m_iAmmoNails < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (m_iQuakeWeapon == IT_NAILGUN) |
|
{ |
|
m_iQuakeWeapon = IT_SUPER_SHOTGUN; |
|
if (m_iAmmoShells < 2) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (m_iQuakeWeapon == IT_SUPER_SHOTGUN) |
|
{ |
|
m_iQuakeWeapon = IT_SHOTGUN; |
|
if (m_iAmmoShells < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
else if (m_iQuakeWeapon == IT_SHOTGUN) |
|
{ |
|
m_iQuakeWeapon = IT_AXE; |
|
} |
|
else if (m_iQuakeWeapon == IT_AXE) |
|
{ |
|
m_iQuakeWeapon = IT_EXTRA_WEAPON; |
|
} |
|
else if (m_iQuakeWeapon == IT_EXTRA_WEAPON) |
|
{ |
|
m_iQuakeWeapon = IT_LIGHTNING; |
|
if (m_iAmmoCells < 1) |
|
bHaveAmmo = FALSE; |
|
} |
|
|
|
|
|
if ( (m_iQuakeItems & m_iQuakeWeapon) && bHaveAmmo ) |
|
{ |
|
W_SetCurrentAmmo(); |
|
return; |
|
} |
|
} |
|
|
|
} |
|
|
|
//================================================================================================ |
|
// WEAPON FUNCTIONS |
|
//================================================================================================ |
|
// Returns true if the inflictor can directly damage the target. Used for explosions and melee attacks. |
|
float Q_CanDamage(CBaseEntity *pTarget, CBaseEntity *pInflictor) |
|
{ |
|
TraceResult trace; |
|
|
|
// bmodels need special checking because their origin is 0,0,0 |
|
if (pTarget->pev->movetype == MOVETYPE_PUSH) |
|
{ |
|
UTIL_TraceLine( pInflictor->pev->origin, 0.5 * (pTarget->pev->absmin + pTarget->pev->absmax), ignore_monsters, NULL, &trace ); |
|
if (trace.flFraction == 1) |
|
return TRUE; |
|
CBaseEntity *pEntity = CBaseEntity::Instance(trace.pHit); |
|
if (pEntity == pTarget) |
|
return TRUE; |
|
return FALSE; |
|
} |
|
|
|
UTIL_TraceLine( pInflictor->pev->origin, pTarget->pev->origin, ignore_monsters, NULL, &trace ); |
|
if (trace.flFraction == 1) |
|
return TRUE; |
|
UTIL_TraceLine( pInflictor->pev->origin, pTarget->pev->origin + Vector(15,15,0), ignore_monsters, NULL, &trace ); |
|
if (trace.flFraction == 1) |
|
return TRUE; |
|
UTIL_TraceLine( pInflictor->pev->origin, pTarget->pev->origin + Vector(-15,-15,0), ignore_monsters, NULL, &trace ); |
|
if (trace.flFraction == 1) |
|
return TRUE; |
|
UTIL_TraceLine( pInflictor->pev->origin, pTarget->pev->origin + Vector(-15,15,0), ignore_monsters, NULL, &trace ); |
|
if (trace.flFraction == 1) |
|
return TRUE; |
|
UTIL_TraceLine( pInflictor->pev->origin, pTarget->pev->origin + Vector(15,-15,0), ignore_monsters, NULL, &trace ); |
|
if (trace.flFraction == 1) |
|
return TRUE; |
|
|
|
return FALSE; |
|
} |
|
|
|
// Quake Bullet firing |
|
void CBasePlayer::Q_FireBullets(int iShots, Vector vecDir, Vector vecSpread) |
|
{ |
|
TraceResult trace; |
|
UTIL_MakeVectors(pev->v_angle); |
|
|
|
Vector vecSrc = pev->origin + (gpGlobals->v_forward * 10); |
|
vecSrc.z = pev->absmin.z + (pev->size.z * 0.7f); |
|
ClearMultiDamage(); |
|
|
|
while ( iShots > 0 ) |
|
{ |
|
Vector vecPath = vecDir + ( RANDOM_FLOAT( -1, 1 ) * vecSpread.x * gpGlobals->v_right ) + ( RANDOM_FLOAT( -1, 1 ) * vecSpread.y * gpGlobals->v_up ); |
|
Vector vecEnd = vecSrc + ( vecPath * 2048 ); |
|
UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT(pev), &trace ); |
|
if (trace.flFraction != 1.0f) |
|
{ |
|
CBaseEntity *pEntity = CBaseEntity::Instance(trace.pHit); |
|
if (pEntity && pEntity->pev->takedamage && pEntity->IsPlayer() ) |
|
{ |
|
pEntity->TraceAttack(pev, 4, vecPath, &trace, DMG_BULLET); |
|
//AddMultiDamage(pev, pEntity, 4, DMG_BULLET); |
|
} |
|
else if ( pEntity && pEntity->pev->takedamage ) |
|
{ |
|
pEntity->TakeDamage( pev, pev, 4, DMG_BULLET ); |
|
} |
|
} |
|
|
|
iShots--; |
|
} |
|
|
|
ApplyMultiDamage( pev, pev ); |
|
} |
|
|
|
#if !defined( CLIENT_DLL ) |
|
// Quake Radius damage |
|
void Q_RadiusDamage( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, CBaseEntity *pIgnore ) |
|
{ |
|
CBaseEntity *pEnt = NULL; |
|
|
|
while ( (pEnt = UTIL_FindEntityInSphere( pEnt, pInflictor->pev->origin, flDamage+40 )) != NULL ) |
|
{ |
|
if (pEnt != pIgnore) |
|
{ |
|
if (pEnt->pev->takedamage) |
|
{ |
|
Vector vecOrg = pEnt->pev->origin + ((pEnt->pev->mins + pEnt->pev->maxs) * 0.5f); |
|
float flPoints = 0.5f * (pInflictor->pev->origin - vecOrg).Length(); |
|
if (flPoints < 0) |
|
flPoints = 0; |
|
flPoints = flDamage - flPoints; |
|
|
|
if (pEnt == pAttacker) |
|
flPoints = flPoints * 0.5f; |
|
if (flPoints > 0) |
|
{ |
|
if ( Q_CanDamage( pEnt, pInflictor ) ) |
|
pEnt->TakeDamage( pInflictor->pev, pAttacker->pev, flPoints, DMG_GENERIC ); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
#endif |
|
|
|
// Lightning hit a target |
|
void LightningHit(CBaseEntity *pTarget, CBaseEntity *pAttacker, Vector vecHitPos, float flDamage, TraceResult *ptr, Vector vecDir ) |
|
{ |
|
|
|
#ifndef CLIENT_DLL |
|
SpawnBlood( vecHitPos, BLOOD_COLOR_RED, flDamage * 1.5f ); |
|
|
|
if ( g_pGameRules->PlayerRelationship( pTarget, pAttacker ) != GR_TEAMMATE ) |
|
{ |
|
|
|
pTarget->TakeDamage( pAttacker->pev, pAttacker->pev, flDamage, DMG_GENERIC ); |
|
pTarget->TraceBleed( flDamage, vecDir, ptr, DMG_BULLET ); // have to use DMG_BULLET or it wont spawn. |
|
|
|
} |
|
#endif |
|
} |
|
|
|
// Lightning Damage |
|
void CBasePlayer::LightningDamage( Vector p1, Vector p2, CBaseEntity *pAttacker, float flDamage, Vector vecDir) |
|
{ |
|
#if !defined( CLIENT_DLL ) |
|
TraceResult trace; |
|
Vector vecThru = (p2 - p1).Normalize(); |
|
vecThru.x = 0 - vecThru.y; |
|
vecThru.y = vecThru.x; |
|
vecThru.z = 0; |
|
vecThru = vecThru * 16; |
|
|
|
CBaseEntity *pEntity1 = NULL; |
|
CBaseEntity *pEntity2 = NULL; |
|
|
|
// Hit first target? |
|
UTIL_TraceLine( p1, p2, dont_ignore_monsters, ENT(pev), &trace ); |
|
CBaseEntity *pEntity = CBaseEntity::Instance(trace.pHit); |
|
if (pEntity && pEntity->pev->takedamage) |
|
{ |
|
LightningHit(pEntity, pAttacker, trace.vecEndPos, flDamage, &trace, vecDir ); |
|
} |
|
pEntity1 = pEntity; |
|
|
|
// Hit second target? |
|
UTIL_TraceLine( p1 + vecThru, p2 + vecThru, dont_ignore_monsters, ENT(pev), &trace ); |
|
pEntity = CBaseEntity::Instance(trace.pHit); |
|
if (pEntity && pEntity != pEntity1 && pEntity->pev->takedamage) |
|
{ |
|
LightningHit(pEntity, pAttacker, trace.vecEndPos, flDamage, &trace, vecDir ); |
|
} |
|
pEntity2 = pEntity; |
|
|
|
// Hit third target? |
|
UTIL_TraceLine( p1 - vecThru, p2 - vecThru, dont_ignore_monsters, ENT(pev), &trace ); |
|
pEntity = CBaseEntity::Instance(trace.pHit); |
|
if (pEntity && pEntity != pEntity1 && pEntity != pEntity2 && pEntity->pev->takedamage) |
|
{ |
|
LightningHit(pEntity, pAttacker, trace.vecEndPos, flDamage, &trace, vecDir ); |
|
} |
|
#endif |
|
} |
|
|
|
//================================================================================================ |
|
// WEAPON FIRING |
|
//================================================================================================ |
|
// Axe |
|
void CBasePlayer::W_FireAxe() |
|
{ |
|
TraceResult trace; |
|
Vector vecSrc = pev->origin + Vector(0, 0, 16); |
|
|
|
// Swing forward 64 units |
|
UTIL_MakeVectors(pev->v_angle); |
|
UTIL_TraceLine( vecSrc, vecSrc + (gpGlobals->v_forward * 64), dont_ignore_monsters, ENT(pev), &trace ); |
|
if (trace.flFraction == 1.0f) |
|
return; |
|
|
|
Vector vecOrg = trace.vecEndPos - gpGlobals->v_forward * 4; |
|
|
|
CBaseEntity *pEntity = CBaseEntity::Instance(trace.pHit); |
|
if (pEntity && pEntity->pev->takedamage) |
|
{ |
|
pEntity->m_bAxHitMe = TRUE; |
|
int iDmg = 20; |
|
if (gpGlobals->deathmatch > 3) |
|
iDmg = 75; |
|
|
|
pEntity->TakeDamage( pev, pev, iDmg, DMG_GENERIC ); |
|
|
|
#ifndef CLIENT_DLL |
|
if ( g_pGameRules->PlayerRelationship( this, pEntity ) != GR_TEAMMATE ) |
|
SpawnBlood( vecOrg, BLOOD_COLOR_RED, iDmg * 4 ); // Make a lot of Blood! |
|
#endif |
|
} |
|
} |
|
|
|
// Single barrel shotgun |
|
void CBasePlayer::W_FireShotgun( int iQuadSound ) |
|
{ |
|
PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usShotgunSingle, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, iQuadSound, 0, 0, 0 ); |
|
|
|
if (gpGlobals->deathmatch != 4 ) |
|
*m_pCurrentAmmo -= 1; |
|
|
|
Vector vecDir = GetAutoaimVector( AUTOAIM_5DEGREES ); |
|
Q_FireBullets(6, vecDir, Vector(0.04, 0.04, 0) ); |
|
} |
|
|
|
void CBasePlayer::W_FireHook( void ) |
|
{ |
|
PLAYBACK_EVENT_FULL( FEV_NOTHOST | FEV_GLOBAL, edict(), g_usHook, 0, (float *)&pev->origin, (float *)&pev->angles, 0.0, 0.0, 0, 0, 0, 0 ); |
|
|
|
Throw_Grapple(); |
|
} |
|
|
|
#ifdef CLIENT_DLL |
|
unsigned short g_usCable; |
|
unsigned short g_usHook; |
|
unsigned short g_usCarried; |
|
|
|
void CBasePlayer::Throw_Grapple( void ) |
|
{ |
|
} |
|
#endif |
|
|
|
// Double barrel shotgun |
|
void CBasePlayer::W_FireSuperShotgun( int iQuadSound ) |
|
{ |
|
if (*m_pCurrentAmmo == 1) |
|
{ |
|
W_FireShotgun( iQuadSound ); |
|
return; |
|
} |
|
|
|
PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usShotgunDouble, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, iQuadSound, 0, 0, 0 ); |
|
|
|
if (gpGlobals->deathmatch != 4 ) |
|
*m_pCurrentAmmo -= 2; |
|
Vector vecDir = GetAutoaimVector( AUTOAIM_5DEGREES ); |
|
Q_FireBullets(14, vecDir, Vector(0.14, 0.08, 0) ); |
|
}; |
|
|
|
// Rocket launcher |
|
void CBasePlayer::W_FireRocket( int iQuadSound ) |
|
{ |
|
PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usRocket, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, iQuadSound, 0, 0, 0 ); |
|
|
|
if (gpGlobals->deathmatch != 4 ) |
|
*m_pCurrentAmmo -= 1; |
|
|
|
// Create the rocket |
|
UTIL_MakeVectors( pev->v_angle ); |
|
Vector vecOrg = pev->origin + (gpGlobals->v_forward * 8) + Vector(0,0,16); |
|
Vector vecDir = GetAutoaimVector( AUTOAIM_5DEGREES ); |
|
CQuakeRocket *pRocket = CQuakeRocket::CreateRocket( vecOrg, vecDir, this ); |
|
} |
|
|
|
// Grenade launcher |
|
void CBasePlayer::W_FireGrenade( int iQuadSound ) |
|
{ |
|
PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usGrenade, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, iQuadSound, 0, 0, 0 ); |
|
|
|
if (gpGlobals->deathmatch != 4 ) |
|
*m_pCurrentAmmo -= 1; |
|
|
|
// Get initial velocity |
|
UTIL_MakeVectors( pev->v_angle ); |
|
Vector vecVelocity; |
|
if ( pev->v_angle.x ) |
|
{ |
|
vecVelocity = gpGlobals->v_forward * 600 + gpGlobals->v_up * 200 + RANDOM_FLOAT(-1,1) * gpGlobals->v_right * 10 + RANDOM_FLOAT(-1,1) * gpGlobals->v_up * 10; |
|
} |
|
else |
|
{ |
|
vecVelocity = GetAutoaimVector( AUTOAIM_5DEGREES ); |
|
vecVelocity = vecVelocity * 600; |
|
vecVelocity.z = 200; |
|
} |
|
|
|
// Create the grenade |
|
CQuakeRocket *pRocket = CQuakeRocket::CreateGrenade( pev->origin, vecVelocity, this ); |
|
} |
|
|
|
// Lightning Gun |
|
void CBasePlayer::W_FireLightning( int iQuadSound ) |
|
{ |
|
if (*m_pCurrentAmmo < 1) |
|
{ |
|
//This should already be IT_LIGHTNING but what the heck. |
|
if ( m_iQuakeWeapon == IT_LIGHTNING ) |
|
{ |
|
PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usLightning, 0, (float *)&pev->origin, (float *)&pev->angles, 0.0, 0.0, 0, 1, 0, 0 ); |
|
|
|
if ( m_pActiveItem ) |
|
((CQuakeGun*)m_pActiveItem)->DestroyEffect(); |
|
} |
|
|
|
m_iQuakeWeapon = W_BestWeapon (); |
|
W_SetCurrentAmmo(); |
|
return; |
|
} |
|
|
|
bool playsound = false; |
|
|
|
// Make lightning sound every 0.6 seconds |
|
if ( m_flLightningTime <= gpGlobals->time ) |
|
{ |
|
playsound = true; |
|
m_flLightningTime = gpGlobals->time + 0.6f; |
|
} |
|
|
|
// explode if under water |
|
if (pev->waterlevel > 1) |
|
{ |
|
if ( (gpGlobals->deathmatch > 3) && (RANDOM_FLOAT(0, 1) <= 0.5f) ) |
|
{ |
|
strcpy( gszQ_DeathType, "selfwater" ); |
|
TakeDamage( pev, pev, 4000, DMG_GENERIC ); |
|
} |
|
else |
|
{ |
|
float flCellsBurnt = *m_pCurrentAmmo; |
|
*m_pCurrentAmmo = 0; |
|
W_SetCurrentAmmo(); |
|
#if !defined( CLIENT_DLL ) |
|
Q_RadiusDamage( this, this, 35 * flCellsBurnt, NULL ); |
|
#endif |
|
return; |
|
} |
|
} |
|
|
|
PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usLightning, 0, (float *)&pev->origin, (float *)&pev->angles, 0.0, 0.0, iQuadSound, 0, playsound, 0 ); |
|
|
|
#if !defined( CLIENT_DLL ) |
|
|
|
if (gpGlobals->deathmatch != 4 ) |
|
*m_pCurrentAmmo -= 1; |
|
|
|
// Lightning bolt effect |
|
TraceResult trace; |
|
Vector vecOrg = pev->origin + Vector(0,0,16); |
|
UTIL_MakeVectors( pev->v_angle ); |
|
UTIL_TraceLine( vecOrg, vecOrg + (gpGlobals->v_forward * 600), ignore_monsters, ENT(pev), &trace ); |
|
|
|
Vector vecDir = gpGlobals->v_forward + ( 0.001f * gpGlobals->v_right ) + ( 0.001f * gpGlobals->v_up ); |
|
// Do damage |
|
LightningDamage(pev->origin, trace.vecEndPos + (gpGlobals->v_forward * 4), this, 30, vecDir ); |
|
|
|
#endif |
|
} |
|
|
|
// Super Nailgun |
|
void CBasePlayer::W_FireSuperSpikes( int iQuadSound ) |
|
{ |
|
PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usSuperSpike, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, iQuadSound, 0, m_iNailOffset > 0.0 ? 1 : 0, 0 ); |
|
|
|
if (gpGlobals->deathmatch != 4 ) |
|
*m_pCurrentAmmo -= 2; |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.1f; |
|
|
|
// Fire the Nail |
|
Vector vecDir = GetAutoaimVector( AUTOAIM_5DEGREES ); |
|
CQuakeNail *pNail = CQuakeNail::CreateSuperNail( pev->origin + Vector(0,0,16), vecDir, this ); |
|
} |
|
|
|
// Nailgun |
|
void CBasePlayer::W_FireSpikes( int iQuadSound ) |
|
{ |
|
// If we're wielding the Super nailgun and we've got ammo for it, fire Super nails |
|
if (*m_pCurrentAmmo >= 2 && m_iQuakeWeapon == IT_SUPER_NAILGUN) |
|
{ |
|
W_FireSuperSpikes( iQuadSound ); |
|
return; |
|
} |
|
|
|
// Swap to next best weapon if this one just ran out |
|
if (*m_pCurrentAmmo < 1) |
|
{ |
|
m_iQuakeWeapon = W_BestWeapon (); |
|
W_SetCurrentAmmo(); |
|
return; |
|
} |
|
|
|
PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usSpike, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, iQuadSound, 0, m_iNailOffset > 0.0f ? 1 : 0, 0 ); |
|
|
|
// Fire left then right |
|
if (m_iNailOffset == 2) |
|
m_iNailOffset = -2; |
|
else |
|
m_iNailOffset = 2; |
|
|
|
if (gpGlobals->deathmatch != 4 ) |
|
*m_pCurrentAmmo -= 1; |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.1f; |
|
|
|
// Fire the nail |
|
UTIL_MakeVectors( pev->v_angle ); |
|
Vector vecDir = GetAutoaimVector( AUTOAIM_5DEGREES ); |
|
CQuakeNail *pNail = CQuakeNail::CreateNail( pev->origin + Vector(0,0,10) + (gpGlobals->v_right * m_iNailOffset), vecDir, this ); |
|
} |
|
|
|
//=============================================================================== |
|
// PLAYER WEAPON USE |
|
//=============================================================================== |
|
void CBasePlayer::W_Attack( int iQuadSound ) |
|
{ |
|
// Out of ammo? |
|
if ( !W_CheckNoAmmo() ) |
|
return; |
|
|
|
if ( m_iQuakeWeapon != IT_LIGHTNING ) |
|
((CBasePlayerWeapon*)m_pActiveItem)->SendWeaponAnim( 1, 1 ); |
|
|
|
if (m_iQuakeWeapon == IT_AXE) |
|
{ |
|
if( m_iRuneStatus == ITEM_RUNE3_FLAG ) |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.3f; |
|
else |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.5f; |
|
|
|
PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usAxeSwing, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, iQuadSound, 0, 0, 0 ); |
|
|
|
// Delay attack for 0.3 |
|
m_flAxeFire = gpGlobals->time + 0.3f; |
|
|
|
PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usAxe, 0.3, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, iQuadSound, 0, 0, 0 ); |
|
|
|
} |
|
else if (m_iQuakeWeapon == IT_SHOTGUN) |
|
{ |
|
if( m_iRuneStatus == ITEM_RUNE3_FLAG ) |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.3f; |
|
else |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.5f; |
|
|
|
W_FireShotgun( iQuadSound ); |
|
} |
|
else if (m_iQuakeWeapon == IT_SUPER_SHOTGUN) |
|
{ |
|
if( m_iRuneStatus == ITEM_RUNE3_FLAG ) |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.4f; |
|
else |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.7f; |
|
|
|
W_FireSuperShotgun( iQuadSound ); |
|
} |
|
else if (m_iQuakeWeapon == IT_NAILGUN) |
|
{ |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.1f; |
|
|
|
W_FireSpikes( iQuadSound ); |
|
} |
|
else if (m_iQuakeWeapon == IT_SUPER_NAILGUN) |
|
{ |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.1f; |
|
W_FireSpikes( iQuadSound ); |
|
} |
|
else if (m_iQuakeWeapon == IT_GRENADE_LAUNCHER) |
|
{ |
|
if( m_iRuneStatus == ITEM_RUNE3_FLAG ) |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.3f; |
|
else |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.6f; |
|
|
|
W_FireGrenade( iQuadSound ); |
|
} |
|
else if (m_iQuakeWeapon == IT_ROCKET_LAUNCHER) |
|
{ |
|
if( m_iRuneStatus == ITEM_RUNE3_FLAG ) |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.4f; |
|
else |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.8f; |
|
|
|
W_FireRocket( iQuadSound ); |
|
} |
|
else if (m_iQuakeWeapon == IT_LIGHTNING) |
|
{ |
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.1f; |
|
|
|
// Play the lightning start sound if gun just started firing |
|
if (m_afButtonPressed & IN_ATTACK) |
|
EMIT_SOUND(ENT(pev), CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM); |
|
|
|
W_FireLightning( iQuadSound ); |
|
} |
|
else if( m_iQuakeWeapon == IT_EXTRA_WEAPON ) |
|
{ |
|
if( !m_bHook_Out ) |
|
W_FireHook(); |
|
|
|
m_flNextAttack = UTIL_WeaponTimeBase() + 0.1f; |
|
} |
|
|
|
// Make player attack |
|
if ( pev->health >= 0 ) |
|
SetAnimation( PLAYER_ATTACK1 ); |
|
} |
|
|
|
|