NS/main/source/mod/AvHGrenade.cpp

463 lines
10 KiB
C++

//======== (C) Copyright 2001 Charles G. Cleveland All rights reserved. =========
//
// The copyright to the contents herein is the property of Charles G. Cleveland.
// The contents may be used and/or copied only with the written permission of
// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Purpose:
//
// $Workfile: AvHGrenade.cpp $
// $Date: 2002/11/22 21:28:16 $
//
//-------------------------------------------------------------------------------
// $Log: AvHGrenade.cpp,v $
// Revision 1.6 2002/11/22 21:28:16 Flayra
// - mp_consistency changes
//
// Revision 1.5 2002/07/24 19:09:16 Flayra
// - Linux issues
//
// Revision 1.4 2002/06/03 16:37:56 Flayra
// - Added different deploy times (this should be refactored a bit more), refactored grenades
//
// Revision 1.3 2002/05/23 02:33:42 Flayra
// - Post-crash checkin. Restored @Backup from around 4/16. Contains changes for last four weeks of development.
//
//===============================================================================
#include "AvHMarineWeapons.h"
#include "AvHPlayer.h"
#ifdef AVH_CLIENT
#include "cl_dll/eventscripts.h"
#include "cl_dll/in_defs.h"
#include "cl_dll/wrect.h"
#include "cl_dll/cl_dll.h"
#endif
#include "../common/hldm.h"
#include "../common/event_api.h"
#include "../common/event_args.h"
#include "../common/vector_util.h"
#include "AvHMarineWeapons.h"
#ifdef AVH_SERVER
#include "AvHGamerules.h"
#include "AvHServerUtil.h"
#endif
#include "../dlls/util.h"
LINK_ENTITY_TO_CLASS(kwGrenade, AvHGrenade);
const int kGrenadeVelocity = 800;
const int kGrenadeRollVelocity = 350;
const float kGrenadeParentVelocityScalar = .4f;
const float kGrenadeGravity = .8f;
const float kGrenadeElasticity = 0.6f;
const float kGrenadePrimeAnimationLength = 0.0f; //2.3f;
const float kGrenadeThrowTimeBeforeRelease = .3f;
const float kGrenadeThrowAnimationLength = 1.5f;
BOOL AvHGrenade::Deploy()
{
// This has three values:
// 0 means inactive
// 1 means trigger throw
// -1 means throw has been recently triggered
m_flStartThrow = 0;
// -1 means inactive
// UTIL_TimeBase or higher means time to throw (>= 0)
m_flReleaseThrow = -1;
return AvHMarineWeapon::Deploy();
}
int AvHGrenade::GetBarrelLength() const
{
return kGRBarrelLength;
}
float AvHGrenade::GetRateOfFire() const
{
return kGrenadePrimeAnimationLength + kGrenadeThrowTimeBeforeRelease;
}
bool AvHGrenade::GetCanBeResupplied() const
{
return false;
}
void AvHGrenade::Init()
{
this->mRange = kGGRange;
this->mDamage = BALANCE_VAR(kHandGrenadeDamage);
}
int AvHGrenade::GetDeployAnimation() const
{
return 5;
}
char* AvHGrenade::GetDeploySound() const
{
return kGRDeploySound;
}
float AvHGrenade::GetDeployTime() const
{
return AvHBasePlayerWeapon::GetDeployTime();
}
bool AvHGrenade::GetFiresUnderwater() const
{
return true;
}
char* AvHGrenade::GetHeavyViewModel() const
{
return kGRHVVModel;
}
int AvHGrenade::GetIdleAnimation() const
{
int theAnim = -1;
if( m_flStartThrow == 0 && m_flReleaseThrow == -1)
{
theAnim = UTIL_SharedRandomLong(this->m_pPlayer->random_seed, 0, 2);
}
return theAnim;
}
bool AvHGrenade::GetIsDroppable() const
{
return false;
}
BOOL AvHGrenade::GetIsWeaponPrimed() const
{
return false;
}
BOOL AvHGrenade::GetIsWeaponPriming() const
{
return false;
}
bool AvHGrenade::GetMustPressTriggerForEachShot() const
{
return false;
}
bool AvHGrenade::ShouldRollGrenade(void) const
{
// If player is crouched, roll grenade instead
return (this->m_pPlayer && FBitSet(this->m_pPlayer->pev->flags, FL_DUCKING));
}
int AvHGrenade::GetShootAnimation() const
{
int theAnimation = 4;
// If player is crouched, play roll animation
if(this->ShouldRollGrenade())
{
theAnimation = 7;
}
return theAnimation;
}
char* AvHGrenade::GetPlayerModel() const
{
return kGRPModel;
}
int AvHGrenade::GetPrimeAnimation() const
{
int theAnimation = 3;
// If player is crouched, play roll animation
if(this->m_pPlayer && FBitSet(this->m_pPlayer->pev->flags, FL_DUCKING))
{
theAnimation = 6;
}
return theAnimation;
}
char* AvHGrenade::GetPrimeSound() const
{
return kGRPrimeSound;
}
char* AvHGrenade::GetViewModel() const
{
return kGRVModel;
}
char* AvHGrenade::GetWorldModel() const
{
return kGRWModel;
}
void AvHGrenade::Holster(int skiplocal)
{
// Important that this goes first to avoid infinite recursion when removing
// the item from the player.
AvHMarineWeapon::Holster(skiplocal);
m_flStartThrow = 0;
m_flReleaseThrow = -1;
if(!this->m_iClip)
{
SetThink(&AvHGrenade::DestroyItem);
this->pev->nextthink = gpGlobals->time + 0.1f;
}
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM);
}
BOOL AvHGrenade::IsUseable(void)
{
// TODO:
return TRUE;
}
void AvHGrenade::PrimaryAttack(bool fireOnAttackUp)
{
if (this->ProcessValidAttack())
{
if (!this->mAttackButtonDownLastFrame)
{
this->PlaybackEvent(this->mStartEvent);
this->mAttackButtonDownLastFrame = true;
}
if (m_flStartThrow == 0)
{
m_flStartThrow = 1;
this->PlaybackEvent(this->mEvent, this->GetPrimeAnimation());
// Set the animation and sound.
this->m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
this->m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
this->m_pPlayer->SetAnimation(PLAYER_PRIME);
// Don't idle/fire until we've finished prime animation
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + kGrenadePrimeAnimationLength;
}
}
else
{
int a = 0;
}
}
void AvHGrenade::FireProjectiles(void)
{
}
int AvHGrenade::GetEmptyShootAnimation() const
{
return -1;
}
float AvHGrenade::GetWeaponPrimeTime() const
{
return BALANCE_VAR(kHandGrenadePrimeTime);
}
BOOL AvHGrenade::PlayEmptySound()
{
// None
return 0;
}
void AvHGrenade::Precache(void)
{
AvHMarineWeapon::Precache();
PRECACHE_UNMODIFIED_SOUND(kGRFireSound1);
PRECACHE_UNMODIFIED_SOUND(kGRDeploySound);
PRECACHE_UNMODIFIED_SOUND(kGRExplodeSound);
PRECACHE_UNMODIFIED_SOUND(kGRHitSound);
this->mEvent = PRECACHE_EVENT(1, kGREventName);
}
bool AvHGrenade::Resupply()
{
return false;
}
void AvHGrenade::SetNextIdle(void)
{
// Idle is treated specially for grenade
if( m_flStartThrow == 0 && m_flReleaseThrow == -1)
{
AvHMarineWeapon::SetNextIdle();
}
}
void AvHGrenade::Spawn()
{
AvHMarineWeapon::Spawn();
Precache();
this->m_iId = AVH_WEAPON_GRENADE;
this->m_iDefaultAmmo = BALANCE_VAR(kHandGrenadeMaxAmmo);
// Set our class name
this->pev->classname = MAKE_STRING(kwsGrenade);
SET_MODEL(ENT(this->pev), kGRWModel);
FallInit();// get ready to fall down.
}
bool AvHGrenade::UsesAmmo(void) const
{
return true;
}
BOOL AvHGrenade::UseDecrement(void)
{
return true;
}
void AvHGrenade::CreateProjectile()
{
#ifdef AVH_SERVER
// Set position and velocity like we do in client event
vec3_t theStartPosition;
UTIL_MakeVectors(this->m_pPlayer->pev->v_angle + this->m_pPlayer->pev->punchangle);
VectorMA(this->m_pPlayer->GetGunPosition(), kGRBarrelLength, gpGlobals->v_forward, theStartPosition);
// Offset it to the right a bit, so it emanates from your hand instead of the center of your body
VectorMA(theStartPosition, 5, gpGlobals->v_right, theStartPosition);
VectorMA(theStartPosition, 8, gpGlobals->v_up, theStartPosition);
// Inherit player velocity for extra skill and finesse
Vector theVelocity;
Vector theInheritedVelocity;
VectorScale(this->m_pPlayer->pev->velocity, kGrenadeParentVelocityScalar, theInheritedVelocity);
if(!this->ShouldRollGrenade())
{
VectorMA(theInheritedVelocity, kGrenadeVelocity, gpGlobals->v_forward, theVelocity);
}
else
{
Vector theTossVelocity(0, 0, 40);
VectorAdd(theInheritedVelocity, theTossVelocity, theInheritedVelocity);
VectorMA(theInheritedVelocity, kGrenadeRollVelocity, gpGlobals->v_forward, theVelocity);
}
// How to handle this? Only generate entity on server, but we should do SOMETHING on the client, no?
CGrenade* theGrenade = AvHSUShootServerGrenade(this->m_pPlayer->pev, theStartPosition, theVelocity, BALANCE_VAR(kHandGrenDetonateTime), true);
ASSERT(theGrenade);
theGrenade->pev->dmg = this->mDamage;
// Make the grenade not very bouncy
theGrenade->pev->gravity = kGrenadeGravity;
theGrenade->pev->friction = 1 - kGrenadeElasticity;
SET_MODEL(ENT(theGrenade->pev), this->GetWorldModel());
theGrenade->pev->avelocity.x = RANDOM_LONG(-300, -200);
// Rotate the grenade to the orientation it would be if it was thrown.
VectorCopy(m_pPlayer->pev->angles, theGrenade->pev->angles);
theGrenade->pev->angles[1] += 100;
#endif
}
void AvHGrenade::ItemPostFrame(void)
{
AvHMarineWeapon::ItemPostFrame();
float theTimeBase = UTIL_WeaponTimeBase();
if(this->m_flReleaseThrow > theTimeBase)
{
float theClientTimePassedThisTick = this->GetTimePassedThisTick();
this->m_flReleaseThrow = max(this->m_flReleaseThrow - theClientTimePassedThisTick, theTimeBase);
}
}
void AvHGrenade::WeaponIdle()
{
if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
{
return;
}
if (m_flStartThrow == 1)
{
// Throw it
this->PlaybackEvent(this->mEvent, GetShootAnimation());
// Set the animation and sound.
this->m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
this->m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
this->m_pPlayer->SetAnimation(PLAYER_ATTACK1);
// Set time to shoot projectile, so it looks right with throw animation
float theTimeToCreateGrenade = UTIL_WeaponTimeBase() + kGrenadeThrowTimeBeforeRelease;
m_flReleaseThrow = theTimeToCreateGrenade;
m_flStartThrow = -1;
}
else if ((m_flStartThrow == -1) && (m_flReleaseThrow == UTIL_WeaponTimeBase()))
{
this->CreateProjectile();
this->DeductCostForShot();
// Finish throw animation
float theAnimationEnd = UTIL_WeaponTimeBase() + kGrenadeThrowAnimationLength;
m_flNextSecondaryAttack = theAnimationEnd;
m_flNextPrimaryAttack = theAnimationEnd;
m_flTimeWeaponIdle = theAnimationEnd;
// We've finished the throw, don't do it again (set both inactive)
m_flStartThrow = 0;
m_flReleaseThrow = -1;
}
else
{
AvHMarineWeapon::WeaponIdle();
if(!this->m_iClip)
{
this->m_pPlayer->SelectLastItem();
}
}
}