Paranoia2/dlls/paranoia_turret.cpp

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");
}
}