forked from FWGS/Paranoia2
319 lines
8.0 KiB
C++
319 lines
8.0 KiB
C++
/***************************************
|
|
*
|
|
* Writen by BUzer for Half-Life: Paranoia modification
|
|
*
|
|
* Static machineguns code
|
|
*
|
|
****************************************/
|
|
|
|
#include "extdll.h"
|
|
#include "util.h"
|
|
#include "cbase.h"
|
|
#include "effects.h"
|
|
#include "weapons.h"
|
|
#include "explode.h"
|
|
#include "monsters.h"
|
|
#include "movewith.h"
|
|
#include "animation.h"
|
|
|
|
#include "player.h"
|
|
|
|
extern int gmsgSpecTank;
|
|
|
|
|
|
class CFuncMachinegun : public CBaseAnimating
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Precache( void );
|
|
void KeyValue( KeyValueData *pkvd );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
virtual int ObjectCaps( void ) { return FCAP_IMPULSE_USE; }
|
|
BOOL OnControls( entvars_t *pevTest );
|
|
void PostFrame( CBaseEntity *pActivator );
|
|
void UpdateClientData( CBasePlayer *client );
|
|
|
|
virtual int Save( CSave &save );
|
|
virtual int Restore( CRestore &restore );
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
|
|
// short m_usEvent;
|
|
float m_flPointHeight;
|
|
float m_flDistUp, m_flDistFwd;
|
|
// float m_flConeHor, m_flConeVer;
|
|
float m_flNextAttack;
|
|
float m_fireRate;
|
|
float m_flDamage;
|
|
// Vector savedPlayerAngles;
|
|
int m_iShouldUpdate;
|
|
// float m_flLastAnimTime;
|
|
int m_iAmmo;
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( func_machinegun, CFuncMachinegun );
|
|
|
|
TYPEDESCRIPTION CFuncMachinegun::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CFuncMachinegun, m_flPointHeight, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CFuncMachinegun, m_flDistUp, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CFuncMachinegun, m_flDistFwd, FIELD_FLOAT ),
|
|
// DEFINE_FIELD( CFuncMachinegun, m_flConeHor, FIELD_FLOAT ),
|
|
// DEFINE_FIELD( CFuncMachinegun, m_flConeVer, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CFuncMachinegun, m_flNextAttack, FIELD_TIME ),
|
|
DEFINE_FIELD( CFuncMachinegun, m_fireRate, FIELD_FLOAT ),
|
|
DEFINE_FIELD( CFuncMachinegun, m_flDamage, FIELD_FLOAT ),
|
|
// DEFINE_FIELD( CFuncMachinegun, savedPlayerAngles, FIELD_VECTOR ),
|
|
// DEFINE_FIELD( CFuncMachinegun, m_flLastAnimTime, FIELD_TIME ),
|
|
DEFINE_FIELD( CFuncMachinegun, m_iAmmo, FIELD_INTEGER ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE( CFuncMachinegun, CBaseAnimating );
|
|
|
|
|
|
void CFuncMachinegun::Precache()
|
|
{
|
|
PRECACHE_MODEL( (char *)STRING(pev->model) );
|
|
PRECACHE_MODEL ("models/shell.mdl");
|
|
|
|
pev->sequence = 0;
|
|
pev->frame = 0;
|
|
pev->framerate = 1;
|
|
ResetSequenceInfo();
|
|
m_fSequenceLoops = TRUE;
|
|
|
|
m_iShouldUpdate = 1;
|
|
}
|
|
|
|
|
|
void CFuncMachinegun::KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "baseheight"))
|
|
{
|
|
m_flPointHeight = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "distfwd"))
|
|
{
|
|
m_flDistFwd = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "distup"))
|
|
{
|
|
m_flDistUp = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
/* else if (FStrEq(pkvd->szKeyName, "conehor"))
|
|
{
|
|
m_flConeHor = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "conever"))
|
|
{
|
|
m_flConeVer = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}*/
|
|
else if (FStrEq(pkvd->szKeyName, "firerate"))
|
|
{
|
|
m_fireRate = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "damage"))
|
|
{
|
|
m_flDamage = atof(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else if (FStrEq(pkvd->szKeyName, "ammo"))
|
|
{
|
|
m_iAmmo = atoi(pkvd->szValue);
|
|
if (m_iAmmo > 999) m_iAmmo = 999;
|
|
if (m_iAmmo < -1) m_iAmmo = -1;
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
CBaseAnimating::KeyValue( pkvd );
|
|
}
|
|
|
|
|
|
void CFuncMachinegun::Spawn()
|
|
{
|
|
Precache();
|
|
|
|
pev->movetype = MOVETYPE_NONE;
|
|
pev->solid = SOLID_BBOX;
|
|
pev->angles.x = 0; // remove pitch
|
|
// m_flLastAnimTime = gpGlobals->time;
|
|
pev->renderfx = 51; // хак для рендерера, чтобы он не интерполировал контроллеры
|
|
|
|
SET_MODEL( ENT(pev), STRING(pev->model) );
|
|
UTIL_SetSize( pev, Vector(-25,-25,0), Vector(25,25,60));
|
|
|
|
ResetSequenceInfo();
|
|
m_fSequenceLoops = TRUE;
|
|
|
|
InitBoneControllers();
|
|
}
|
|
|
|
|
|
BOOL CFuncMachinegun::OnControls( entvars_t *pevTest )
|
|
{
|
|
Vector vecToPlayer = pevTest->origin - pev->origin;
|
|
vecToPlayer.z = 0;
|
|
|
|
if ( vecToPlayer.Length() > 50 )
|
|
return FALSE;
|
|
|
|
UTIL_MakeVectors(pev->angles);
|
|
vecToPlayer = vecToPlayer.Normalize();
|
|
|
|
if (DotProduct(vecToPlayer, gpGlobals->v_forward) > -0.7)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void CFuncMachinegun::PostFrame( CBaseEntity *pActivator )
|
|
{
|
|
Vector plAngles = pActivator->pev->angles;
|
|
while (plAngles.y < 0) plAngles.y += 360;
|
|
|
|
float yawAngle = plAngles.y - pev->angles.y;
|
|
float pitchAngle = pActivator->pev->angles.x * -3;
|
|
SetBoneController( 0, yawAngle );
|
|
SetBoneController( 1, pitchAngle );
|
|
|
|
StudioFrameAdvance(); // ^%&*(#%$%^@# !!!!
|
|
|
|
// return to idle after fire anim
|
|
if (m_fSequenceFinished)
|
|
{
|
|
pev->sequence = 0;
|
|
pev->frame = 0;
|
|
ResetSequenceInfo();
|
|
// ALERT(at_console, "return to idle\n");
|
|
m_fSequenceLoops = TRUE;
|
|
}
|
|
|
|
if ( gpGlobals->time < m_flNextAttack )
|
|
return;
|
|
|
|
// ALERT(at_console, "current ammo: %d\n", m_iAmmo);
|
|
|
|
if ( pActivator->pev->button & IN_ATTACK && (m_iAmmo > 0 || m_iAmmo == -1))
|
|
{
|
|
// fire
|
|
Vector vecForward, vecSrc, vecAngles;
|
|
vecAngles = pActivator->pev->angles;
|
|
vecAngles.x = vecAngles.x * -3; // invert anf scale pitch
|
|
UTIL_MakeVectorsPrivate( vecAngles, vecForward, NULL, NULL );
|
|
GetAttachment(0, vecSrc, vecAngles);
|
|
|
|
pev->sequence = 1; // sounds, muzzleflashes, and shells will go by anim event
|
|
pev->frame = 0;
|
|
ResetSequenceInfo();
|
|
m_fSequenceLoops = FALSE;
|
|
|
|
if( !m_flDamage ) m_flDamage = gSkillData.monDmg12MM;
|
|
FireBullets( 1, vecSrc, vecForward, Vector( 0, 0, 0 ), 4096, BULLET_NORMAL, m_flDamage, pActivator->pev );
|
|
if (m_iAmmo > 0) m_iAmmo--;
|
|
|
|
// update ammo counter
|
|
MESSAGE_BEGIN( MSG_ONE, gmsgSpecTank, NULL, pActivator->pev );
|
|
WRITE_BYTE( 2 ); // ammo update
|
|
WRITE_LONG(m_iAmmo);
|
|
MESSAGE_END();
|
|
|
|
// HACKHACK -- make some noise (that the AI can hear)
|
|
if ( pActivator->IsPlayer() )
|
|
((CBasePlayer *)pActivator)->m_iWeaponVolume = LOUD_GUN_VOLUME;
|
|
|
|
m_flNextAttack = gpGlobals->time + ( 1.0f / m_fireRate );
|
|
}
|
|
|
|
// ALERT(at_console, "current sequence: %d\n", pev->sequence);
|
|
}
|
|
|
|
|
|
void CFuncMachinegun::UpdateClientData( CBasePlayer *client )
|
|
{
|
|
if (m_iShouldUpdate)
|
|
{
|
|
Vector vecPoint = pev->origin + Vector(0, 0, m_flPointHeight);
|
|
float coneHor = GetControllerBound( 0 );
|
|
float coneVer = GetControllerBound( 1 );
|
|
|
|
MESSAGE_BEGIN( MSG_ONE, gmsgSpecTank, NULL, client->pev );
|
|
WRITE_BYTE( 1 ); // tank is on
|
|
WRITE_COORD(vecPoint.x);
|
|
WRITE_COORD(vecPoint.y);
|
|
WRITE_COORD(vecPoint.z);
|
|
WRITE_COORD(pev->angles.y); // write default yaw
|
|
WRITE_COORD(coneHor); // write cone
|
|
WRITE_COORD(coneVer); //
|
|
WRITE_COORD(m_flDistFwd);
|
|
WRITE_COORD(m_flDistUp);
|
|
WRITE_LONG(m_iAmmo);
|
|
MESSAGE_END();
|
|
|
|
m_iShouldUpdate = 0;
|
|
}
|
|
}
|
|
|
|
void CFuncMachinegun::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if (!pActivator->IsPlayer())
|
|
{
|
|
ALERT(at_console, "non player activating func_machinegun!\n");
|
|
return;
|
|
}
|
|
|
|
if (useType == USE_SET && value == 2) // called by playerthink, update position
|
|
{
|
|
PostFrame( pActivator );
|
|
}
|
|
else if (useType == USE_SET && value == 3) // update client data
|
|
{
|
|
UpdateClientData( (CBasePlayer*)pActivator );
|
|
}
|
|
else if (useType == USE_OFF) // turn off
|
|
{
|
|
CBasePlayer *player = (CBasePlayer *)pActivator;
|
|
// player->pev->angles = savedPlayerAngles;
|
|
MESSAGE_BEGIN( MSG_ONE, gmsgSpecTank, NULL, player->pev );
|
|
WRITE_BYTE( 0 ); // tank is off
|
|
MESSAGE_END();
|
|
|
|
pev->sequence = 0;
|
|
pev->frame = 0;
|
|
ResetSequenceInfo();
|
|
m_fSequenceLoops = TRUE;
|
|
|
|
if ( player->m_pActiveItem )
|
|
player->m_pActiveItem->Deploy();
|
|
|
|
player->m_iHideHUD &= ~HIDEHUD_WEAPONS;
|
|
}
|
|
else // turn on
|
|
{
|
|
// is player in valid zone
|
|
if ( OnControls(pActivator->pev) )
|
|
{
|
|
CBasePlayer *player = (CBasePlayer *)pActivator;
|
|
player->m_pSpecTank = this;
|
|
m_iShouldUpdate = 1;
|
|
// savedPlayerAngles = player->pev->angles;
|
|
// player->pev->angles = pev->angles;
|
|
player->m_iHideHUD |= HIDEHUD_WEAPONS;
|
|
|
|
if ( player->m_pActiveItem )
|
|
{
|
|
player->m_pActiveItem->Holster( true );
|
|
player->pev->weaponmodel = 0;
|
|
player->pev->viewmodel = 0;
|
|
}
|
|
}
|
|
// else
|
|
// ALERT(at_console, "player is not in valid zone\n");
|
|
}
|
|
}
|