hlsdk-xash3d/dlls/rpg.cpp

292 lines
7.7 KiB
C++

/***
*
* 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.
*
****/
#if !OEM_BUILD
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#include "gamerules.h"
#if !CLIENT_DLL
LINK_ENTITY_TO_CLASS( laser_spot, CLaserSpot )
//=========================================================
//=========================================================
CLaserSpot *CLaserSpot::CreateSpot( void )
{
CLaserSpot *pSpot = GetClassPtr( (CLaserSpot *)NULL );
pSpot->Spawn();
pSpot->pev->classname = MAKE_STRING( "laser_spot" );
return pSpot;
}
//=========================================================
//=========================================================
void CLaserSpot::Spawn( void )
{
Precache();
pev->movetype = MOVETYPE_NONE;
pev->solid = SOLID_NOT;
pev->rendermode = kRenderGlow;
pev->renderfx = kRenderFxNoDissipation;
pev->renderamt = 255;
SET_MODEL( ENT( pev ), "sprites/laserdot.spr" );
UTIL_SetOrigin( pev, pev->origin );
}
//=========================================================
// Suspend- make the laser sight invisible.
//=========================================================
void CLaserSpot::Suspend( float flSuspendTime )
{
pev->effects |= EF_NODRAW;
SetThink( &CLaserSpot::Revive );
pev->nextthink = gpGlobals->time + flSuspendTime;
}
//=========================================================
// Revive - bring a suspended laser sight back.
//=========================================================
void CLaserSpot::Revive( void )
{
pev->effects &= ~EF_NODRAW;
SetThink( NULL );
}
void CLaserSpot::Precache( void )
{
PRECACHE_MODEL( "sprites/laserdot.spr" );
}
LINK_ENTITY_TO_CLASS( rpg_rocket, CRpgRocket )
//=========================================================
//=========================================================
CRpgRocket *CRpgRocket::CreateRpgRocket( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CRpg *pLauncher )
{
CRpgRocket *pRocket = GetClassPtr( (CRpgRocket *)NULL );
UTIL_SetOrigin( pRocket->pev, vecOrigin );
pRocket->pev->angles = vecAngles;
pRocket->Spawn();
pRocket->SetTouch( &CRpgRocket::RocketTouch );
pRocket->m_hLauncher = pLauncher;// remember what RPG fired me.
pLauncher->m_cActiveRockets++;// register this missile as active for the launcher
pRocket->pev->owner = pOwner->edict();
return pRocket;
}
void CRpgRocket::Explode( TraceResult *pTrace, int bitsDamageType )
{
if( CRpg *pLauncher = GetLauncher())
{
// my launcher is still around, tell it I'm dead.
pLauncher->m_cActiveRockets--;
m_hLauncher = 0;
}
STOP_SOUND( edict(), CHAN_VOICE, "weapons/rocket1.wav" );
CGrenade::Explode( pTrace, bitsDamageType );
}
CRpg *CRpgRocket::GetLauncher( void )
{
return (CRpg*)( (CBaseEntity*)m_hLauncher );
}
//=========================================================
//=========================================================
void CRpgRocket::Spawn( void )
{
Precache();
// motor
pev->movetype = MOVETYPE_BOUNCE;
pev->solid = SOLID_BBOX;
SET_MODEL( ENT( pev ), "models/rpgrocket.mdl" );
UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) );
UTIL_SetOrigin( pev, pev->origin );
pev->classname = MAKE_STRING( "rpg_rocket" );
SetThink( &CRpgRocket::IgniteThink );
SetTouch( &CGrenade::ExplodeTouch );
pev->angles.x -= 30.0f;
UTIL_MakeVectors( pev->angles );
pev->angles.x = -( pev->angles.x + 30.0f );
pev->velocity = gpGlobals->v_forward * 250.0f;
pev->gravity = 0.5f;
pev->nextthink = gpGlobals->time + 0.4f;
pev->dmg = gSkillData.plrDmgRPG;
}
//=========================================================
//=========================================================
void CRpgRocket::RocketTouch( CBaseEntity *pOther )
{
if( CRpg *pLauncher = GetLauncher())
{
// my launcher is still around, tell it I'm dead.
pLauncher->m_cActiveRockets--;
m_hLauncher = 0;
}
STOP_SOUND( edict(), CHAN_VOICE, "weapons/rocket1.wav" );
ExplodeTouch( pOther );
}
//=========================================================
//=========================================================
void CRpgRocket::Precache( void )
{
PRECACHE_MODEL( "models/rpgrocket.mdl" );
m_iTrail = PRECACHE_MODEL( "sprites/smoke.spr" );
PRECACHE_SOUND( "weapons/rocket1.wav" );
}
void CRpgRocket::IgniteThink( void )
{
// pev->movetype = MOVETYPE_TOSS;
pev->movetype = MOVETYPE_FLY;
pev->effects |= EF_LIGHT;
// make rocket sound
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/rocket1.wav", 1, 0.5f );
// rocket trail
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
WRITE_BYTE( TE_BEAMFOLLOW );
WRITE_SHORT( entindex() ); // entity
WRITE_SHORT( m_iTrail ); // model
WRITE_BYTE( 40 ); // life
WRITE_BYTE( 5 ); // width
WRITE_BYTE( 224 ); // r, g, b
WRITE_BYTE( 224 ); // r, g, b
WRITE_BYTE( 255 ); // r, g, b
WRITE_BYTE( 255 ); // brightness
MESSAGE_END(); // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS)
m_flIgniteTime = gpGlobals->time;
// set to follow laser spot
SetThink( &CRpgRocket::FollowThink );
pev->nextthink = gpGlobals->time + 0.1f;
}
void CRpgRocket::FollowThink( void )
{
CBaseEntity *pOther = NULL;
Vector vecTarget;
Vector vecDir;
float flDist, flMax, flDot;
TraceResult tr;
UTIL_MakeAimVectors( pev->angles );
vecTarget = gpGlobals->v_forward;
flMax = 4096;
// Examine all entities within a reasonable radius
while( ( pOther = UTIL_FindEntityByClassname( pOther, "laser_spot" ) ) != NULL )
{
UTIL_TraceLine( pev->origin, pOther->pev->origin, dont_ignore_monsters, ENT( pev ), &tr );
// ALERT( at_console, "%f\n", tr.flFraction );
if( tr.flFraction >= 0.9f )
{
vecDir = pOther->pev->origin - pev->origin;
flDist = vecDir.Length();
vecDir = vecDir.Normalize();
flDot = DotProduct( gpGlobals->v_forward, vecDir );
if( ( flDot > 0 ) && ( flDist * ( 1 - flDot ) < flMax ) )
{
flMax = flDist * ( 1 - flDot );
vecTarget = vecDir;
}
}
}
pev->angles = UTIL_VecToAngles( vecTarget );
// this acceleration and turning math is totally wrong, but it seems to respond well so don't change it.
float flSpeed = pev->velocity.Length();
if( gpGlobals->time - m_flIgniteTime < 1.0f )
{
pev->velocity = pev->velocity * 0.2f + vecTarget * ( flSpeed * 0.8f + 400.0f );
if( pev->waterlevel == 3 )
{
// go slow underwater
if( pev->velocity.Length() > 300.0f )
{
pev->velocity = pev->velocity.Normalize() * 300.0f;
}
UTIL_BubbleTrail( pev->origin - pev->velocity * 0.1f, pev->origin, 4 );
}
else
{
if( pev->velocity.Length() > 2000.0f )
{
pev->velocity = pev->velocity.Normalize() * 2000.0f;
}
}
}
else
{
if( pev->effects & EF_LIGHT )
{
pev->effects = 0;
STOP_SOUND( ENT( pev ), CHAN_VOICE, "weapons/rocket1.wav" );
}
pev->velocity = pev->velocity * 0.2f + vecTarget * flSpeed * 0.798f;
if( pev->waterlevel == 0 && pev->velocity.Length() < 1500.0f )
Detonate();
}
// ALERT( at_console, "%.0f\n", flSpeed );
if( CRpg *pLauncher = GetLauncher())
{
if( ( pev->origin - pLauncher->pev->origin ).Length() > 8192 || gpGlobals->time - m_flIgniteTime > 6.0f )
{
// my launcher is still around, tell it I'm dead.
pLauncher->m_cActiveRockets--;
m_hLauncher = 0;
}
}
if( UTIL_PointContents( pev->origin ) == CONTENTS_SKY )
Detonate();
pev->nextthink = gpGlobals->time + 0.1f;
}
#endif
#endif