648 lines
15 KiB
C++
648 lines
15 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Logfile:: /Quake 2 Engine/Sin/code/game/pulserifle.cpp $
|
|
// $Revision:: 69 $
|
|
// $Author:: Aldie $
|
|
// $Date:: 3/02/99 9:14p $
|
|
//
|
|
// Copyright (C) 1998 by Ritual Entertainment, Inc.
|
|
// All rights reserved.
|
|
//
|
|
// This source is may not be distributed and/or modified without
|
|
// expressly written permission by Ritual Entertainment, Inc.
|
|
//
|
|
// $Log:: /Quake 2 Engine/Sin/code/game/pulserifle.cpp $
|
|
//
|
|
// 69 3/02/99 9:14p Aldie
|
|
// Added CTF game code
|
|
//
|
|
// 68 11/16/98 3:11a Jimdose
|
|
// pulse now takes gravity of owner
|
|
//
|
|
// 67 11/16/98 2:11a Jimdose
|
|
// removed unused variable in Shoot
|
|
//
|
|
// 66 11/15/98 12:22a Markd
|
|
// Fixed pre-caching issues
|
|
//
|
|
// 65 11/13/98 3:30p Markd
|
|
// put in more precaching on weapons
|
|
//
|
|
// 64 10/26/98 2:50p Aldie
|
|
// Fixed a bug with checking of NULL owners
|
|
//
|
|
// 63 10/24/98 12:42a Markd
|
|
// changed origins to worldorigins where appropriate
|
|
//
|
|
// 62 10/22/98 7:57p Markd
|
|
// put in proper pre-caching in all the classes
|
|
//
|
|
// 61 10/20/98 8:26p Markd
|
|
// Added Attacker to DamageSurface stuff
|
|
//
|
|
// 60 10/19/98 12:07a Jimdose
|
|
// made all code use fast checks for inheritance (no text lookups when
|
|
// possible)
|
|
// isSubclassOf no longer requires ::_classinfo()
|
|
//
|
|
// 59 10/16/98 10:22p Aldie
|
|
// Updated single player damage settings
|
|
//
|
|
// 58 10/16/98 9:50p Aldie
|
|
// Added SecondaryAmmo command
|
|
//
|
|
// 57 10/15/98 2:32p Aldie
|
|
// Updated model name for pulsebomb
|
|
//
|
|
// 56 10/10/98 9:18p Aldie
|
|
// Tweak damage
|
|
//
|
|
// 55 10/10/98 5:58p Aldie
|
|
// More quantumdestab fixes
|
|
//
|
|
// 54 10/09/98 11:56p Markd
|
|
// Added GenericPulseRifle
|
|
//
|
|
// 53 10/06/98 2:49p Aldie
|
|
// Tweak NextAttack
|
|
//
|
|
// 52 10/05/98 10:39p Aldie
|
|
// Fixed rank and updated damage.
|
|
//
|
|
// 51 10/04/98 10:28p Aldie
|
|
// Added multiple weapon changes. Damage, flashes, quantum stuff
|
|
//
|
|
// 50 10/03/98 1:09p Aldie
|
|
// Tweak the effects again
|
|
//
|
|
// 49 10/02/98 7:19p Aldie
|
|
// Orient the shockwave
|
|
//
|
|
// 48 10/02/98 5:47p Aldie
|
|
// New effects - yet again
|
|
//
|
|
// 47 10/01/98 4:01p Markd
|
|
// Added Archive and Unarchive functions
|
|
//
|
|
// 46 9/29/98 11:45p Aldie
|
|
// New effect for mode1
|
|
//
|
|
// 45 9/21/98 5:31p Markd
|
|
// took out owner out of projectile subclasses, working on archive and
|
|
// unarchive
|
|
//
|
|
// 44 9/18/98 8:14p Markd
|
|
// rewrote surface system so that surfaces are now damaged by surface name
|
|
// instead of by surfinfo
|
|
//
|
|
// 43 9/16/98 8:58p Aldie
|
|
// Added ability to do a hold down weapon charge
|
|
//
|
|
// 42 9/09/98 3:56p Aldie
|
|
// New lightning effect
|
|
//
|
|
// 41 9/01/98 3:05p Markd
|
|
// Rewrote explosion code
|
|
//
|
|
// 40 8/31/98 7:45p Aldie
|
|
// Updated surface data structure and removed surfinfo field
|
|
//
|
|
// 39 8/29/98 9:45p Jimdose
|
|
// Added call info to G_Trace
|
|
//
|
|
// 38 8/29/98 5:27p Markd
|
|
// added specialfx, replaced misc with specialfx where appropriate
|
|
//
|
|
// 37 8/18/98 8:12p Aldie
|
|
// Added dual mode weapons to base class
|
|
//
|
|
// 36 8/01/98 3:03p Aldie
|
|
// Client side muzzle flash (dynamic light)
|
|
//
|
|
// 35 7/25/98 7:10p Markd
|
|
// Put in EV_Removes for demo
|
|
//
|
|
// 34 7/23/98 6:17p Aldie
|
|
// Updated damage system and fixed some damage related bugs. Also put tracers
|
|
// back to the way they were, and added gib event to funcscriptmodels
|
|
//
|
|
// 33 7/22/98 9:57p Markd
|
|
// Defined weapon type
|
|
//
|
|
// 32 7/22/98 5:14p Aldie
|
|
// Fixed NextAttack time
|
|
//
|
|
// 31 7/21/98 1:10p Aldie
|
|
// Added meansofdeath to obituaries
|
|
//
|
|
// 30 7/01/98 4:39p Aldie
|
|
// Put Beaus' model explosion back in
|
|
//
|
|
// 29 6/30/98 6:48p Aldie
|
|
// Removed a printf
|
|
//
|
|
// 28 6/30/98 12:40p Aldie
|
|
// Fixed some bugs with vid_restart issue
|
|
//
|
|
// 27 6/29/98 8:19p Aldie
|
|
// Updated shockwave
|
|
//
|
|
// 26 6/25/98 7:32p Aldie
|
|
// Adding damage wall
|
|
//
|
|
// 25 6/19/98 9:30p Jimdose
|
|
// Moved gun orientation code to Weapon
|
|
//
|
|
// 24 6/17/98 6:30p Aldie
|
|
// Updated ammo requirements
|
|
//
|
|
// 23 6/17/98 5:42p Aldie
|
|
// Updated lots and made the beam do some damage.
|
|
//
|
|
// 22 6/15/98 9:09p Aldie
|
|
// Updated the special fx for beams trailing from the pulse.
|
|
//
|
|
// 21 6/15/98 12:25p Aldie
|
|
// Updated pulse beam parms
|
|
//
|
|
// 20 6/15/98 10:38a Aldie
|
|
// New version of pulse stuff
|
|
//
|
|
// 19 6/10/98 2:10p Aldie
|
|
// Updated damage function.
|
|
//
|
|
// 18 5/14/98 9:14p Markd
|
|
// Changed models
|
|
//
|
|
// 17 5/13/98 6:21p Markd
|
|
// Made pulse rifle burn wall as well as retrigger more often
|
|
//
|
|
// 16 5/03/98 4:36p Jimdose
|
|
// Changed Vector class
|
|
//
|
|
// 15 4/20/98 1:56p Markd
|
|
// SINED decelration is now in def file
|
|
//
|
|
// 14 4/18/98 3:12p Markd
|
|
// Changed view weapon naming convention
|
|
//
|
|
// 13 4/08/98 12:06a Jimdose
|
|
// Added temporary beam effect
|
|
//
|
|
// 12 4/07/98 6:41p Jimdose
|
|
// Rewrote weapon code.
|
|
// Added order to rank
|
|
//
|
|
// 11 4/02/98 4:20p Jimdose
|
|
// Tweaked for DM
|
|
//
|
|
// 10 3/30/98 9:55p Jimdose
|
|
// Changed location of .def files
|
|
//
|
|
// 9 3/30/98 2:34p Jimdose
|
|
// Moved firing to BulletWeapon to make more general
|
|
// Added Ammo
|
|
// Added world models
|
|
//
|
|
// 8 3/28/98 8:55p Jimdose
|
|
// Created file
|
|
//
|
|
// DESCRIPTION:
|
|
// Pulse rifle
|
|
//
|
|
|
|
#include "g_local.h"
|
|
#include "bullet.h"
|
|
#include "pulserifle.h"
|
|
#include "specialfx.h"
|
|
#include "misc.h"
|
|
#include "explosion.h"
|
|
#include "surface.h"
|
|
|
|
#define PULSE_MODE 0
|
|
|
|
// Projectile portion of the pulse rifle
|
|
|
|
template class EXPORT_FROM_DLL SafePtr<Beam>;
|
|
typedef SafePtr<Beam> BeamPtr;
|
|
|
|
class EXPORT_FROM_DLL Pulse : public Projectile
|
|
{
|
|
public:
|
|
CLASS_PROTOTYPE( Pulse );
|
|
|
|
Pulse();
|
|
virtual void Setup( Entity *owner, Vector pos, Vector dir );
|
|
virtual void Explode( Event *ev );
|
|
};
|
|
|
|
CLASS_DECLARATION( Projectile, Pulse, NULL );
|
|
|
|
Event EV_Pulse_UpdateBeams("update_beams");
|
|
Event EV_Pulse_Remove("remove_beams");
|
|
|
|
ResponseDef Pulse::Responses[] =
|
|
{
|
|
{ &EV_Touch, ( Response )Pulse::Explode },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
Pulse::Pulse()
|
|
{
|
|
}
|
|
|
|
void Pulse::Explode
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
Entity *other;
|
|
Entity *owner;
|
|
int damg;
|
|
Vector v;
|
|
Vector norm;
|
|
Vector shockangles;
|
|
Entity *pulseexpl;
|
|
|
|
other = ev->GetEntity( 1 );
|
|
assert( other );
|
|
|
|
if ( other->isSubclassOf( Teleporter ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( other->entnum == this->owner )
|
|
{
|
|
return;
|
|
}
|
|
|
|
owner = G_GetEntity( this->owner );
|
|
|
|
if ( !owner )
|
|
owner = world;
|
|
|
|
stopsound( CHAN_VOICE );
|
|
setSolidType( SOLID_NOT );
|
|
|
|
// Hit the shy, so remove everything
|
|
if ( HitSky() )
|
|
{
|
|
PostEvent( EV_Remove, 0 );
|
|
return;
|
|
}
|
|
|
|
damg = 50 + ( int )G_Random( 25 );
|
|
|
|
// Single player packs a bigger punch
|
|
if ( !deathmatch->value && owner->isClient() )
|
|
damg *= 1.5;
|
|
|
|
if ( other->takedamage )
|
|
other->Damage( this, owner, damg, worldorigin, velocity, level.impact_trace.plane.normal, 32, 0, MOD_PULSE, -1, -1, 1.0f );
|
|
|
|
// Damage the surface
|
|
surfaceManager.DamageSurface ( &level.impact_trace, damg, owner );
|
|
|
|
damg = 100;
|
|
|
|
// Single player packs a bigger punch
|
|
if ( !deathmatch->value && owner->isClient() )
|
|
damg *= 1.5;
|
|
|
|
// Do an explosion but don't hurt other, since he already took damage.
|
|
RadiusDamage( this, owner, damg, other, MOD_PULSE );
|
|
|
|
v = velocity;
|
|
v.normalize();
|
|
v = worldorigin - v * 36;
|
|
|
|
norm = level.impact_trace.plane.normal;
|
|
norm.x = -norm.x;
|
|
norm.y = -norm.y;
|
|
shockangles = norm.toAngles();
|
|
shockangles.z = G_Random( 360 );
|
|
|
|
// Start up the shockwave effect
|
|
|
|
pulseexpl = new Entity;
|
|
pulseexpl->setModel( "pulseshock.def" );
|
|
pulseexpl->setOrigin( v );
|
|
pulseexpl->worldorigin.copyTo(pulseexpl->edict->s.old_origin);
|
|
pulseexpl->setAngles( shockangles );
|
|
pulseexpl->setMoveType( MOVETYPE_NONE );
|
|
pulseexpl->setSolidType( SOLID_NOT );
|
|
pulseexpl->RandomAnimate( "pulseexplode", NULL );
|
|
pulseexpl->PostEvent( EV_Remove, 0.1f );
|
|
FlashPlayers(v, 0.1, 0.1, 1, 0.5, 500 );
|
|
|
|
PostEvent( EV_Remove, 0 );
|
|
}
|
|
|
|
void Pulse::Setup
|
|
(
|
|
Entity *owner,
|
|
Vector pos,
|
|
Vector dir
|
|
)
|
|
|
|
{
|
|
Event *ev1, *ev2;
|
|
Vector forward, right, up;
|
|
Vector end, delta;
|
|
|
|
this->owner = owner->entnum;
|
|
edict->owner = owner->edict;
|
|
|
|
// Align the projectile
|
|
angles = dir.toAngles();
|
|
angles[ PITCH ] = -angles[ PITCH ];
|
|
setAngles( angles );
|
|
edict->s.angles[ROLL] = rand() % 360;
|
|
|
|
// Flies like a rocket
|
|
setMoveType( MOVETYPE_TOSS );
|
|
setSolidType( SOLID_BBOX );
|
|
edict->clipmask = MASK_PROJECTILE;
|
|
setModel( "sprites/pulsebomb.spr" );
|
|
edict->s.effects |= EF_AUTO_ANIMATE;
|
|
|
|
// Set the flying velocity
|
|
velocity = dir * 1000;
|
|
gravity = 0.7;
|
|
|
|
SetGravityAxis( owner->gravaxis );
|
|
|
|
takedamage = DAMAGE_NO;
|
|
|
|
// Set the light and effects
|
|
edict->s.renderfx |= RF_DLIGHT;
|
|
edict->s.effects |= EF_PULSE;
|
|
edict->s.radius = 100;
|
|
edict->s.color_r = 0.1f;
|
|
edict->s.color_g = 0.1f;
|
|
edict->s.color_b = 0.9f;
|
|
|
|
// setup ambient thrust sound
|
|
ev1 = new Event( EV_RandomEntitySound );
|
|
ev1->AddString( "thrust" );
|
|
ProcessEvent( ev1 );
|
|
|
|
// Set size and origin
|
|
setSize( "-1 -1 -1", "1 1 1" );
|
|
setOrigin( pos );
|
|
worldorigin.copyTo(edict->s.old_origin);
|
|
|
|
// Remove the projectile in the future
|
|
ev2 = new Event( EV_Pulse_Remove );
|
|
PostEvent( ev2, 30 );
|
|
}
|
|
|
|
CLASS_DECLARATION( BulletWeapon, PulseRifle, "weapon_pulserifle" );
|
|
|
|
ResponseDef PulseRifle::Responses[] =
|
|
{
|
|
{ &EV_Weapon_Shoot, ( Response )PulseRifle::Shoot },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
PulseRifle::PulseRifle()
|
|
{
|
|
#ifdef SIN_DEMO
|
|
PostEvent( EV_Remove, 0 );
|
|
return;
|
|
#endif
|
|
SetModels( "pulse2.def", "view_pulse2.def" );
|
|
SetAmmo( "BulletPulse", 10, 50 );
|
|
SetSecondaryAmmo( "BulletPulse", 5, 50 );
|
|
SetRank( 80, 80 );
|
|
SetType( WEAPON_2HANDED_LO );
|
|
dualmode = true;
|
|
modelIndex( "pulse_ammo.def" );
|
|
modelIndex( "beam.def" );
|
|
modelIndex( "pulseshock.def" );
|
|
modelIndex( "sprites/pulsebomb.spr" );
|
|
modelIndex( "sprites/pulse_muzzle.spr" );
|
|
}
|
|
|
|
|
|
// This is the trace that the laser portion of this weapon does.
|
|
void PulseRifle::TraceAttack
|
|
(
|
|
Vector start,
|
|
Vector end,
|
|
int damage,
|
|
trace_t *trace,
|
|
int numricochets,
|
|
int kick,
|
|
int dflags
|
|
)
|
|
|
|
{
|
|
Vector org;
|
|
Vector dir;
|
|
int surfflags;
|
|
int surftype;
|
|
Entity *ent;
|
|
|
|
if ( HitSky( trace ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
dir = end - start;
|
|
dir.normalize();
|
|
|
|
org = end - dir * 4;
|
|
|
|
if ( !trace->surface )
|
|
{
|
|
surfflags = 0;
|
|
surftype = 0;
|
|
}
|
|
else
|
|
{
|
|
surfflags = trace->surface->flags;
|
|
surftype = SURFACETYPE_FROM_FLAGS( surfflags );
|
|
surfaceManager.DamageSurface( trace, damage, owner );
|
|
}
|
|
|
|
ent = trace->ent->entity;
|
|
|
|
if ( ent && ent->takedamage )
|
|
{
|
|
if ( trace->intersect.valid )
|
|
{
|
|
// We hit a valid group so send in location based damage
|
|
ent->Damage( this,
|
|
owner,
|
|
damage,
|
|
trace->endpos,
|
|
dir,
|
|
trace->plane.normal,
|
|
kick,
|
|
dflags,
|
|
MOD_PULSELASER,
|
|
trace->intersect.parentgroup,
|
|
-1,
|
|
trace->intersect.damage_multiplier );
|
|
}
|
|
else
|
|
{
|
|
// We didn't hit any groups, so send in generic damage
|
|
ent->Damage( this,
|
|
owner,
|
|
damage,
|
|
trace->endpos,
|
|
dir,
|
|
trace->plane.normal,
|
|
kick,
|
|
dflags,
|
|
MOD_PULSELASER,
|
|
-1,
|
|
-1,
|
|
1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void PulseRifle::PulseExplosion
|
|
(
|
|
trace_t *trace
|
|
)
|
|
|
|
{
|
|
Vector org, v;
|
|
float damg;
|
|
Entity *ent;
|
|
float kick = 250;
|
|
Vector shockangles;
|
|
Vector norm;
|
|
Vector tempvec;
|
|
float points;
|
|
Vector endpos;
|
|
float radius;
|
|
|
|
damg = 50 + ( int )G_Random( 20 );
|
|
RadiusDamage( this, owner, damg, NULL, MOD_PULSE );
|
|
|
|
VectorCopy( trace->dir, tempvec.vec3() );
|
|
endpos = trace->endpos - ( tempvec * 8 );
|
|
|
|
norm = trace->plane.normal;
|
|
norm.x = -norm.x;
|
|
norm.y = -norm.y;
|
|
shockangles = norm.toAngles();
|
|
shockangles.z = G_Random( 360 );
|
|
|
|
RandomPositionedSound( endpos, "impact_smallexplosion", 1.0, CHAN_AUTO, ATTN_NORM );
|
|
|
|
radius = damg + 50;
|
|
ent = findradius( NULL, endpos, radius );
|
|
while( ent )
|
|
{
|
|
if ( ( ent->takedamage ) &&
|
|
( ent->movetype != MOVETYPE_NONE ) &&
|
|
( ent->movetype != MOVETYPE_BOUNCE ) &&
|
|
( ent->movetype != MOVETYPE_PUSH ) &&
|
|
( ent->movetype != MOVETYPE_STOP ) )
|
|
{
|
|
org = ent->centroid;
|
|
v = org - endpos;
|
|
points = v.length();
|
|
v.normalize();
|
|
ent->velocity += (v * kick);
|
|
|
|
points *= (float)0.5;
|
|
|
|
if ( points < 0 )
|
|
{
|
|
points = 0;
|
|
}
|
|
|
|
points = damg - points;
|
|
|
|
if ( points > 0 )
|
|
{
|
|
if ( this->CanDamage( ent ) )
|
|
{
|
|
ent->Damage(this, owner, points,
|
|
org, v, vec_zero, points,
|
|
DAMAGE_RADIUS, MOD_PULSE,
|
|
-1, -1, 1.0f );
|
|
}
|
|
}
|
|
}
|
|
ent = findradius( ent, endpos, radius );
|
|
}
|
|
}
|
|
|
|
void PulseRifle::Shoot
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
|
|
Vector pos;
|
|
Vector end;
|
|
Vector dir;
|
|
Vector delta;
|
|
trace_t trace;
|
|
float dist;
|
|
float length;
|
|
float damg;
|
|
|
|
assert( owner );
|
|
if ( !owner )
|
|
{
|
|
return;
|
|
}
|
|
|
|
GetMuzzlePosition( &pos, &dir );
|
|
|
|
if ( weaponmode == PRIMARY )
|
|
{
|
|
Pulse *pulse;
|
|
|
|
pulse = new Pulse;
|
|
pulse->Setup( owner, pos, dir );
|
|
NextAttack( 0.5 );
|
|
}
|
|
else
|
|
{
|
|
// Fire the beam
|
|
length = ev->GetInteger( 1 );
|
|
end = pos + dir * length;
|
|
trace = G_Trace( pos, vec_zero, vec_zero, end, owner, MASK_SHOT, "PulseRifle::Shoot" );
|
|
delta = trace.endpos - pos;
|
|
dist = delta.length();
|
|
|
|
// Set the pitch of this weapon so the client can use it to fire bullets in the right directions
|
|
dir = Vector( owner->orientation[ 0 ] );
|
|
angles = dir.toAngles();
|
|
setAngles( angles );
|
|
|
|
if ( ctf->value )
|
|
damg = 30;
|
|
else
|
|
damg = 15;
|
|
TraceAttack( pos, trace.endpos, damg, &trace, 0, 0, 0 );
|
|
NextAttack( 0 );
|
|
}
|
|
}
|
|
|
|
CLASS_DECLARATION( PulseRifle, GenericPulseRifle, "weapon_genericpulserifle" );
|
|
|
|
ResponseDef GenericPulseRifle::Responses[] =
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
GenericPulseRifle::GenericPulseRifle()
|
|
{
|
|
SetModels( NULL, "view_pulse2.def" );
|
|
}
|
|
|