1077 lines
25 KiB
C++
1077 lines
25 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Logfile:: /Quake 2 Engine/Sin/code/game/quantumd.cpp $
|
|
// $Revision:: 46 $
|
|
// $Author:: Aldie $
|
|
// $Date:: 11/18/98 8:28p $
|
|
//
|
|
// 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/quantumd.cpp $
|
|
//
|
|
// 46 11/18/98 8:28p Aldie
|
|
// Added NOION check for quantum overload
|
|
//
|
|
// 45 11/15/98 12:22a Markd
|
|
// Fixed pre-caching issues
|
|
//
|
|
// 44 11/09/98 3:46a Aldie
|
|
// Fixed health death problems
|
|
//
|
|
// 43 10/26/98 2:50p Aldie
|
|
// Fixed a bug with checking of NULL owners
|
|
//
|
|
// 42 10/24/98 12:42a Markd
|
|
// changed origins to worldorigins where appropriate
|
|
//
|
|
// 41 10/22/98 7:57p Markd
|
|
// put in proper pre-caching in all the classes
|
|
//
|
|
// 40 10/22/98 5:52p Aldie
|
|
// Went back to single mode firing
|
|
//
|
|
// 39 10/21/98 2:28a Aldie
|
|
// Fixed bug with destruct function
|
|
//
|
|
// 38 10/20/98 8:26p Markd
|
|
// Added Attacker to DamageSurface stuff
|
|
//
|
|
// 37 10/19/98 12:07a Jimdose
|
|
// made all code use fast checks for inheritance (no text lookups when
|
|
// possible)
|
|
// isSubclassOf no longer requires ::_classinfo()
|
|
//
|
|
// 36 10/18/98 7:58p Aldie
|
|
// Changed quantum to do a full trace
|
|
//
|
|
// 35 10/16/98 10:22p Aldie
|
|
// Updated single player damage settings
|
|
//
|
|
// 34 10/16/98 9:50p Aldie
|
|
// Added SecondaryAmmo command and flame effect
|
|
//
|
|
// 33 10/14/98 12:12a Aldie
|
|
// Took out seeking
|
|
//
|
|
// 32 10/13/98 7:33p Aldie
|
|
// Fixed event problem
|
|
//
|
|
// 31 10/13/98 7:14p Aldie
|
|
// Added seeking
|
|
//
|
|
// 30 10/11/98 5:33p Aldie
|
|
// Tweak damage
|
|
//
|
|
// 29 10/11/98 12:03a Aldie
|
|
// Change velocity
|
|
//
|
|
// 28 10/10/98 9:59p Aldie
|
|
// Added radius damage
|
|
//
|
|
// 27 10/10/98 5:58p Aldie
|
|
// More quantumdestab fixes
|
|
//
|
|
// 26 10/06/98 9:17p Aldie
|
|
// Make sure you kill all with quantum
|
|
//
|
|
// 25 10/06/98 2:51p Aldie
|
|
// Fix killing of the player for quantum
|
|
//
|
|
// 24 10/05/98 10:42p Aldie
|
|
// Fixed dropping of quantum bug
|
|
//
|
|
// 23 10/04/98 10:38p Markd
|
|
// Commented out player trapped in quantum code for the time being
|
|
//
|
|
// 22 10/04/98 10:28p Aldie
|
|
// Added multiple weapon changes. Damage, flashes, quantum stuff
|
|
//
|
|
// 21 10/01/98 8:01p Aldie
|
|
// Tweaked power
|
|
//
|
|
// 20 10/01/98 4:01p Markd
|
|
// Added Archive and Unarchive functions
|
|
//
|
|
// 19 9/30/98 1:26p Aldie
|
|
// Fixed damage function when quantum self destructs
|
|
//
|
|
// 18 9/29/98 11:46p Aldie
|
|
// Added unfreeze and killsight effects
|
|
//
|
|
// 17 9/25/98 2:59p Aldie
|
|
// Change rate of ammo
|
|
//
|
|
// 16 9/23/98 10:08p Aldie
|
|
// Added self destruct mechanism
|
|
//
|
|
// 15 9/22/98 8:10p Aldie
|
|
// Freeze stuff
|
|
//
|
|
// 14 9/21/98 5:31p Markd
|
|
// took out owner out of projectile subclasses, working on archive and
|
|
// unarchive
|
|
//
|
|
// 13 9/21/98 1:34a Aldie
|
|
// Made the quantum eat ammo
|
|
//
|
|
// 12 9/20/98 5:12p Aldie
|
|
// New effects for quantum
|
|
//
|
|
// 11 9/17/98 4:37p Aldie
|
|
// Temporary checkin
|
|
//
|
|
// 10 9/16/98 8:58p Aldie
|
|
// Added ability to do a hold down weapon charge
|
|
//
|
|
// 9 9/16/98 4:03p Aldie
|
|
// Intermediate checkin
|
|
//
|
|
// 8 9/11/98 3:54p Aldie
|
|
// Put in releasefire
|
|
//
|
|
// 7 8/18/98 5:51p Aldie
|
|
// Added support for dual mode weapons.
|
|
//
|
|
// 6 8/18/98 2:32p Aldie
|
|
// Fixed some bugs with animation control
|
|
//
|
|
// 5 8/06/98 10:53p Aldie
|
|
// Added weapon tweaks and kickback. Also modified blast radius damage and
|
|
// rocket jumping.
|
|
//
|
|
// 4 8/03/98 1:16p Aldie
|
|
// Changed ammo type
|
|
//
|
|
// 3 7/29/98 5:56p Aldie
|
|
// Changed classname
|
|
//
|
|
// 2 7/29/98 3:38p Aldie
|
|
// First version of QD
|
|
//
|
|
// 1 7/29/98 3:15p Aldie
|
|
//
|
|
// DESCRIPTION:
|
|
// Quantum Destabilizer
|
|
|
|
#include "quantumd.h"
|
|
#include "specialfx.h"
|
|
#include "explosion.h"
|
|
#include "player.h"
|
|
#include "surface.h"
|
|
|
|
#define ION_MODE 1
|
|
#define DESTAB_MODE 2
|
|
|
|
class EXPORT_FROM_DLL IonBurst : public Projectile
|
|
{
|
|
private:
|
|
float power;
|
|
|
|
public:
|
|
CLASS_PROTOTYPE( IonBurst );
|
|
|
|
IonBurst();
|
|
virtual void Setup( Entity *owner, Vector pos, float power );
|
|
virtual void Explode( Event *ev );
|
|
virtual void Archive( Archiver &arc );
|
|
virtual void Unarchive( Archiver &arc );
|
|
};
|
|
|
|
EXPORT_FROM_DLL void IonBurst::Archive
|
|
(
|
|
Archiver &arc
|
|
)
|
|
{
|
|
Projectile::Archive( arc );
|
|
|
|
arc.WriteFloat( power );
|
|
}
|
|
|
|
EXPORT_FROM_DLL void IonBurst::Unarchive
|
|
(
|
|
Archiver &arc
|
|
)
|
|
{
|
|
Projectile::Unarchive( arc );
|
|
|
|
arc.ReadFloat( &power );
|
|
}
|
|
|
|
class EXPORT_FROM_DLL Ion : public Projectile
|
|
{
|
|
private:
|
|
float power;
|
|
|
|
public:
|
|
CLASS_PROTOTYPE( Ion );
|
|
|
|
Ion();
|
|
virtual void Setup( Entity *owner, Vector pos, Vector dir, float power );
|
|
virtual void Explode( Event *ev );
|
|
qboolean CanSee( Entity *ent );
|
|
virtual void Seek( Event *ev );
|
|
float AdjustAngle( float maxadjust, float currangle, float targetangle );
|
|
virtual void Archive( Archiver &arc );
|
|
virtual void Unarchive( Archiver &arc );
|
|
};
|
|
|
|
EXPORT_FROM_DLL void Ion::Archive
|
|
(
|
|
Archiver &arc
|
|
)
|
|
{
|
|
Projectile::Archive( arc );
|
|
|
|
arc.WriteFloat( power );
|
|
}
|
|
|
|
EXPORT_FROM_DLL void Ion::Unarchive
|
|
(
|
|
Archiver &arc
|
|
)
|
|
{
|
|
Projectile::Unarchive( arc );
|
|
|
|
arc.ReadFloat( &power );
|
|
}
|
|
|
|
CLASS_DECLARATION( Projectile, IonBurst, NULL );
|
|
|
|
ResponseDef IonBurst::Responses[] =
|
|
{
|
|
{ &EV_Touch, ( Response )IonBurst::Explode },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
IonBurst::IonBurst
|
|
(
|
|
)
|
|
|
|
{
|
|
}
|
|
|
|
void IonBurst::Explode
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
Entity *other;
|
|
Entity *owner;
|
|
float damg;
|
|
|
|
other = ev->GetEntity( 1 );
|
|
assert( other );
|
|
|
|
// Do damage to what we hit
|
|
if ( other->isSubclassOf( Teleporter ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( other->entnum == this->owner )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Hit the sky, so remove everything
|
|
if ( HitSky() )
|
|
{
|
|
PostEvent( EV_Remove, 0 );
|
|
return;
|
|
}
|
|
|
|
owner = G_GetEntity( this->owner );
|
|
|
|
if ( !owner )
|
|
owner = world;
|
|
|
|
damg = 20 + power * 20;
|
|
|
|
if ( other->takedamage )
|
|
{
|
|
other->Damage( this, owner, damg, worldorigin, velocity, level.impact_trace.plane.normal, 32, 0, MOD_ION, -1, -1, 1.0f );
|
|
PostEvent( EV_Remove, 0 );
|
|
}
|
|
}
|
|
|
|
void IonBurst::Setup
|
|
(
|
|
Entity *owner,
|
|
Vector pos,
|
|
float power
|
|
)
|
|
|
|
{
|
|
Event *event;
|
|
|
|
this->owner = owner->entnum;
|
|
edict->owner = owner->edict;
|
|
|
|
setMoveType( MOVETYPE_BOUNCE );
|
|
setSolidType( SOLID_BBOX );
|
|
edict->clipmask = MASK_PROJECTILE;
|
|
SetGravityAxis( owner->gravaxis );
|
|
showModel();
|
|
|
|
setModel( "qp_burst.def" );
|
|
RandomAnimate( "flyburst", NULL );
|
|
|
|
this->power = power;
|
|
|
|
// Set the flying velocity
|
|
velocity[0] = 300.0 * crandom() + 200 * power;
|
|
velocity[1] = 300.0 * crandom() + 200 * power;
|
|
velocity[2] = 300.0 + 300.0 * random() + 200 * power;
|
|
|
|
takedamage = DAMAGE_NO;
|
|
|
|
// Set the light and effects
|
|
edict->s.renderfx |= RF_DLIGHT;
|
|
edict->s.effects |= EF_EVERYFRAME;
|
|
edict->s.radius = 200;
|
|
edict->s.color_r = 1.0f;
|
|
edict->s.color_g = 0.2;
|
|
edict->s.color_b = 0.1;
|
|
|
|
setScale( 0.3 );
|
|
// Set size and origin
|
|
setSize( "-2 -2 -2", "2 2 2" );
|
|
setOrigin( pos );
|
|
worldorigin.copyTo(edict->s.old_origin);
|
|
|
|
event = new Event( EV_Remove );
|
|
PostEvent( event, 1.2 );
|
|
}
|
|
|
|
CLASS_DECLARATION( Projectile, Ion, NULL );
|
|
|
|
Event EV_Ion_Seek( "ionseek" );
|
|
|
|
ResponseDef Ion::Responses[] =
|
|
{
|
|
{ &EV_Touch, ( Response )Ion::Explode },
|
|
{ &EV_Ion_Seek, ( Response )Ion::Seek },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
Ion::Ion()
|
|
{
|
|
}
|
|
|
|
qboolean Ion::CanSee
|
|
(
|
|
Entity *ent
|
|
)
|
|
|
|
{
|
|
Vector delta;
|
|
Vector start;
|
|
Vector end;
|
|
trace_t trace;
|
|
|
|
start = worldorigin;
|
|
end = ent->centroid;
|
|
|
|
// Check if he's visible
|
|
trace = G_Trace( start, vec_zero, vec_zero, end, this, MASK_OPAQUE, "Ion::CanSee" );
|
|
if ( trace.fraction == 1.0 || trace.ent == ent->edict )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
float Ion::AdjustAngle
|
|
(
|
|
float maxadjust,
|
|
float currangle,
|
|
float targetangle
|
|
)
|
|
|
|
{
|
|
float dangle;
|
|
float magangle;
|
|
|
|
dangle = currangle - targetangle;
|
|
|
|
if ( dangle )
|
|
{
|
|
magangle = ( float )fabs( dangle );
|
|
if ( magangle < maxadjust )
|
|
{
|
|
currangle = targetangle;
|
|
}
|
|
else
|
|
{
|
|
if ( magangle > 180.0f )
|
|
{
|
|
maxadjust = -maxadjust;
|
|
}
|
|
if ( dangle > 0 )
|
|
{
|
|
maxadjust = -maxadjust;
|
|
}
|
|
currangle += maxadjust;
|
|
}
|
|
}
|
|
|
|
while( currangle >= 360.0f )
|
|
{
|
|
currangle -= 360.0f;
|
|
}
|
|
|
|
while( currangle < 0.0f )
|
|
{
|
|
currangle += 360.0f;
|
|
}
|
|
|
|
return currangle;
|
|
}
|
|
|
|
|
|
void Ion::Seek
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
Entity *ent;
|
|
Vector delta;
|
|
float dist;
|
|
Entity *bestent = NULL;
|
|
float bestdist = 999999;
|
|
Vector newangles, newdir;
|
|
|
|
ent = findradius( NULL, worldorigin.vec3(), 256 );
|
|
while( ent )
|
|
{
|
|
if ( ( ent->entnum != owner ) && ( ent->takedamage ) && ent->isSubclassOf( Sentient ) )
|
|
{
|
|
delta = worldorigin - ent->centroid;
|
|
dist = delta.length();
|
|
|
|
if ( ( dist < bestdist ) && CanSee( ent ) )
|
|
{
|
|
bestent = ent;
|
|
bestdist = dist;
|
|
}
|
|
}
|
|
ent = findradius( ent, worldorigin.vec3(), 1000 );
|
|
}
|
|
|
|
if (!bestent)
|
|
{
|
|
PostEvent( ev, FRAMETIME );
|
|
return;
|
|
}
|
|
|
|
newdir = bestent->centroid - worldorigin;
|
|
newdir.normalize();
|
|
velocity = newdir * 250;
|
|
|
|
angles = newdir.toAngles();
|
|
angles[ PITCH ] = -angles[ PITCH ];
|
|
setAngles( angles );
|
|
|
|
PostEvent( ev, FRAMETIME );
|
|
}
|
|
|
|
void Ion::Explode
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
Entity *other;
|
|
Entity *owner;
|
|
int damg;
|
|
Vector v;
|
|
|
|
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;
|
|
|
|
setSolidType( SOLID_NOT );
|
|
|
|
// Hit the sky, so remove everything
|
|
if ( HitSky() )
|
|
{
|
|
PostEvent( EV_Remove, 0 );
|
|
return;
|
|
}
|
|
|
|
damg = 50 + ( power * 200 );
|
|
|
|
// 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, 0, 0, MOD_ION, -1, -1, 1.0f );
|
|
|
|
if ( other->isSubclassOf( Sentient ) )
|
|
{
|
|
Sentient *sent = (Sentient * )other;
|
|
sent->ProcessEvent( EV_Sentient_Freeze );
|
|
sent->PostEvent( EV_Sentient_UnFreeze, 1 );
|
|
}
|
|
}
|
|
|
|
v = velocity;
|
|
v.normalize();
|
|
v = worldorigin - v * 36;
|
|
|
|
RadiusDamage( this, owner, damg, this, MOD_ION );
|
|
|
|
edict->s.effects &= ~EF_EVERYFRAME;
|
|
// Process the explode animation, then remove this thing
|
|
RandomAnimate( "explode", EV_Remove );
|
|
|
|
#if 0
|
|
// Fire off some gib bursts
|
|
for ( i=0; i<3; i++ )
|
|
{
|
|
IonBurst *burst;
|
|
|
|
burst = new IonBurst;
|
|
burst->Setup( owner, v, power );
|
|
}
|
|
#endif
|
|
|
|
FlashPlayers(v, 1, 1, 1, 0.5, 500 );
|
|
}
|
|
|
|
void Ion::Setup
|
|
(
|
|
Entity *owner,
|
|
Vector pos,
|
|
Vector dir,
|
|
float power
|
|
)
|
|
|
|
{
|
|
Event *event;
|
|
|
|
this->owner = owner->entnum;
|
|
edict->owner = owner->edict;
|
|
|
|
this->power = power;
|
|
// Align the projectile
|
|
angles = dir.toAngles();
|
|
angles[ PITCH ] = -angles[ PITCH ];
|
|
setAngles( angles );
|
|
edict->s.angles[ROLL] = rand() % 360;
|
|
|
|
// Flies like a rocket
|
|
setMoveType( MOVETYPE_FLYMISSILE );
|
|
setSolidType( SOLID_BBOX );
|
|
edict->clipmask = MASK_PROJECTILE;
|
|
setModel( "qp_burst.def" );
|
|
|
|
RandomAnimate( "idle", NULL );
|
|
|
|
//PostEvent( EV_Ion_Seek, 0.1f );
|
|
// Set the flying velocity
|
|
velocity = dir * 1000;
|
|
gravity = 0;
|
|
|
|
avelocity = Vector( "0 0 2000" );
|
|
|
|
takedamage = DAMAGE_NO;
|
|
|
|
// Set the light and effects
|
|
edict->s.renderfx |= RF_DLIGHT;
|
|
edict->s.effects |= EF_EVERYFRAME;
|
|
edict->s.radius = 200;
|
|
edict->s.color_r = 1.0f;
|
|
edict->s.color_g = 0;
|
|
edict->s.color_b = 0;
|
|
|
|
// Adjust scale by power
|
|
edict->s.scale *= power;
|
|
edict->s.scale += 0.2f;
|
|
|
|
// Set size and origin
|
|
setSize( "-1 -1 -1", "1 1 1" );
|
|
setOrigin( pos );
|
|
worldorigin.copyTo(edict->s.old_origin);
|
|
|
|
event = new Event( EV_Remove );
|
|
PostEvent( event, 20 );
|
|
}
|
|
|
|
CLASS_DECLARATION( BulletWeapon, QuantumDestabilizer, "weapon_quantumdestabilizer" );
|
|
|
|
Event EV_Quantum_EatAmmo( "eatammo" );
|
|
Event EV_Quantum_Destruct( "destruct" );
|
|
Event EV_Quantum_StartSelfDestruct( "destruct_time" );
|
|
Event EV_Quantum_SentientOverload( "sentient_overload" );
|
|
|
|
ResponseDef QuantumDestabilizer::Responses[] =
|
|
{
|
|
{ &EV_Weapon_Shoot, ( Response )QuantumDestabilizer::Shoot },
|
|
{ &EV_Quantum_EatAmmo, ( Response )QuantumDestabilizer::EatAmmo },
|
|
{ &EV_Quantum_Destruct, ( Response )QuantumDestabilizer::Destruct },
|
|
{ &EV_Quantum_StartSelfDestruct, ( Response )QuantumDestabilizer::StartSelfDestruct },
|
|
{ &EV_Quantum_SentientOverload, ( Response )QuantumDestabilizer::SentientOverload },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
QuantumDestabilizer::QuantumDestabilizer
|
|
(
|
|
)
|
|
|
|
{
|
|
#ifdef SIN_DEMO
|
|
PostEvent( EV_Remove, 0 );
|
|
return;
|
|
#endif
|
|
SetModels( "quantum.def", "view_quantum.def" );
|
|
modelIndex( "qp_burst.def" );
|
|
modelIndex( "sprites/qp_exhaust.spr" );
|
|
modelIndex( "sprites/qp_sphere.spr" );
|
|
modelIndex( "sprites/shockwave2.spr" );
|
|
modelIndex( "sphere3.def" );
|
|
gi.soundindex( "weapons/quantum/burst.wav" );
|
|
|
|
SetAmmo( "BulletPulse", 20, 100 );
|
|
//SetSecondaryAmmo( "BulletPulse", 5, 100);
|
|
SetRank( 90, 90 );
|
|
SetType( WEAPON_2HANDED_LO );
|
|
trapped_sent = NULL;
|
|
//dualmode = true;
|
|
}
|
|
|
|
void QuantumDestabilizer::EatAmmo
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
Event *event;
|
|
Ammo * ammo;
|
|
|
|
assert( owner );
|
|
if ( owner && owner->isClient() && !( owner->flags & FL_GODMODE ) )
|
|
{
|
|
if ( ammotype.length() )
|
|
{
|
|
ammo = ( Ammo * )owner->FindItem( ammotype.c_str() );
|
|
|
|
// Eat 1 ammo per charge up
|
|
if ( !ammo || !ammo->Use( 1 ) )
|
|
{
|
|
// Ran out of ammo, fire this sucker
|
|
event = new Event( EV_Sentient_ReleaseAttack );
|
|
event->AddFloat( level.time - owner->firedowntime );
|
|
owner->ProcessEvent( event );
|
|
owner->firedown = false;
|
|
}
|
|
else
|
|
{
|
|
PostEvent( EV_Quantum_EatAmmo, 0.1 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void QuantumDestabilizer::Destruct
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
Entity *ent;
|
|
|
|
CancelEventsOfType( EV_Quantum_EatAmmo );
|
|
|
|
CreateExplosion( owner->centroid, 200, 1.0f, true, this, owner, owner );
|
|
|
|
ent = findradius( NULL, owner->centroid, 512 );
|
|
while( ent )
|
|
{
|
|
if ( ( ent != owner ) && ( !ent->deadflag ) && ( ent->takedamage ) && !(ent->flags & FL_NOION ) )
|
|
{
|
|
ent->Damage( this, owner, 10000+ent->health, ent->worldorigin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR|DAMAGE_NO_SKILL, MOD_ION, -1, -1, 1.0f );
|
|
}
|
|
ent = findradius( ent, owner->centroid, 512 );
|
|
}
|
|
|
|
// Make owner deceased
|
|
owner->Damage( this, owner, 10000+owner->health, worldorigin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR|DAMAGE_NO_SKILL, MOD_ION_DESTRUCT, -1, -1, 1.0f );
|
|
}
|
|
|
|
void QuantumDestabilizer::SentientOverload
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
#if 0
|
|
if ( trapped_sent )
|
|
{
|
|
if ( trapped_sent->isClient() )
|
|
{
|
|
Player *player = (Player * )(Sentient *)trapped_sent;
|
|
|
|
// Clear this so we don't get thrown out of the gun when it gets dropped
|
|
trapped_sent = NULL;
|
|
|
|
player->trappedInQuantum = false;
|
|
player->edict->svflags &= ~SVF_HIDEOWNER;
|
|
player->edict->owner = NULL;
|
|
player->origin = owner->origin;
|
|
player->ProcessEvent( EV_Sentient_UnFreeze );
|
|
player->showModel();
|
|
player->setSolidType( SOLID_BBOX );
|
|
player->unlink();
|
|
|
|
SpawnTeleportEffect(player->worldorigin, 123);
|
|
KillBox( player );
|
|
|
|
player->setOrigin( player->origin );
|
|
player->worldorigin.copyTo(player->edict->s.old_origin);
|
|
player->SetCamera( NULL );
|
|
}
|
|
else
|
|
{
|
|
// Kill the owner
|
|
owner->health = 0;
|
|
owner->Damage( this, owner, 1000, worldorigin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR|DAMAGE_NO_SKILL, MOD_ION_DESTRUCT, -1, -1, 1.0f );
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void QuantumDestabilizer::StartSelfDestruct
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
float time = ev->GetFloat( 1 );
|
|
PostEvent( EV_Quantum_Destruct, time );
|
|
}
|
|
|
|
void QuantumDestabilizer::ReleaseFire
|
|
(
|
|
float holdfiretime
|
|
)
|
|
|
|
{
|
|
if ( weaponmode == PRIMARY )
|
|
{
|
|
CancelEventsOfType( EV_Quantum_EatAmmo );
|
|
CancelEventsOfType( EV_Quantum_Destruct );
|
|
|
|
if ( holdfiretime > 5 )
|
|
holdfiretime = 5;
|
|
if ( holdfiretime < 0 )
|
|
holdfiretime = 0;
|
|
|
|
power = holdfiretime / 5.0f;
|
|
|
|
RandomAnimate( "releasefire", EV_Weapon_DoneFiring );
|
|
last_attack_time = level.time;
|
|
}
|
|
}
|
|
|
|
qboolean QuantumDestabilizer::ShootSentient
|
|
(
|
|
Vector pos,
|
|
Vector dir
|
|
)
|
|
|
|
{
|
|
return false;
|
|
#if 0
|
|
Vector end;
|
|
trace_t trace;
|
|
|
|
if ( trapped_sent )
|
|
{
|
|
// Check to see if there is empty space in front of the gun
|
|
end = pos + dir * 50;
|
|
trace = G_Trace( pos, trapped_sent->mins, trapped_sent->maxs, end, this, MASK_SOLID, "QuantumDestabilizer::ShootSentient" );
|
|
|
|
if ( trace.fraction != 1.0 )
|
|
return false;
|
|
|
|
trapped_sent->origin = pos + dir *25;
|
|
trapped_sent->origin -= (trapped_sent->maxs - trapped_sent->mins) * 0.5f;
|
|
trapped_sent->velocity = pos + dir * 750;
|
|
trapped_sent->setOrigin( trapped_sent->origin );
|
|
trapped_sent->worldorigin.copyTo(trapped_sent->edict->s.old_origin);
|
|
trapped_sent->ProcessEvent( EV_Sentient_UnFreeze );
|
|
trapped_sent->showModel();
|
|
trapped_sent->setSolidType( SOLID_BBOX );
|
|
trapped_sent->setMoveType( MOVETYPE_HURL );
|
|
|
|
if ( trapped_sent->isClient() )
|
|
{
|
|
Player *player = (Player *)(Sentient *)trapped_sent;
|
|
|
|
player->edict->svflags &= ~SVF_HIDEOWNER;
|
|
player->edict->owner = NULL;
|
|
player->trappedInQuantum = false;
|
|
}
|
|
|
|
trapped_sent = NULL;
|
|
CancelEventsOfType( EV_Quantum_SentientOverload );
|
|
|
|
return( true );
|
|
}
|
|
else
|
|
{
|
|
gi.dprintf("No sentient in quantum destabilizer" );
|
|
return( false );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void QuantumDestabilizer::SuckSentient
|
|
(
|
|
Vector pos,
|
|
Vector dir
|
|
)
|
|
|
|
{
|
|
#if 0
|
|
Vector end;
|
|
trace_t trace;
|
|
|
|
end = pos + dir * 8192;
|
|
trace = G_FullTrace( pos, vec_zero, vec_zero, end, 5, owner, MASK_SHOT, "QuantumDestabilizer::SuckSentient" );
|
|
|
|
// Check to see if we hit a sentient
|
|
if ( trace.ent )
|
|
{
|
|
if ( trace.ent->entity->isSubclassOf( Sentient ) )
|
|
{
|
|
// Freeze them, hide the model, set notsolid
|
|
Sentient *sent = ( Sentient * )trace.ent->entity;
|
|
sent->ProcessEvent( EV_Sentient_Freeze );
|
|
sent->hideModel();
|
|
sent->setSolidType( SOLID_NOT );
|
|
|
|
// Do the implosion tess effect
|
|
TesselateModel( sent,
|
|
1,
|
|
1000,
|
|
dir,
|
|
100,
|
|
1.0f,
|
|
0,
|
|
vec3_origin,
|
|
TESSELATE_IMPLODE,
|
|
126
|
|
);
|
|
|
|
// If they are a client, set some flags so they don't see the owner
|
|
// of this weapon.
|
|
if ( sent->isClient() )
|
|
{
|
|
Player *player;
|
|
|
|
player = ( Player * )sent;
|
|
player->trappedInQuantum = true;
|
|
player->SetCamera( owner );
|
|
player->edict->svflags |= SVF_HIDEOWNER;
|
|
player->edict->owner = owner->edict;
|
|
}
|
|
|
|
trapped_sent = sent;
|
|
|
|
// We have a sentient trapped, set a destruct timer for 5 seconds
|
|
PostEvent( EV_Quantum_SentientOverload, 5 );
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// This is the trace that the laser portion of this weapon does.
|
|
void QuantumDestabilizer::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_QUANTUM,
|
|
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_QUANTUM,
|
|
-1,
|
|
-1,
|
|
1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
void QuantumDestabilizer::Shoot
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
Vector pos,dir;
|
|
Vector end,delta;
|
|
Ion *ion = new Ion;
|
|
|
|
assert( owner );
|
|
if ( !owner )
|
|
{
|
|
return;
|
|
}
|
|
|
|
GetMuzzlePosition( &pos, &dir );
|
|
ion->Setup( owner, pos, dir, power );
|
|
NextAttack( 1 );
|
|
|
|
#if 0
|
|
if ( weaponmode == PRIMARY )
|
|
{
|
|
Ion *ion = new Ion;
|
|
ion->Setup( owner, pos, dir, power );
|
|
NextAttack( 1 );
|
|
}
|
|
else
|
|
{
|
|
length = ev->GetInteger( 1 );
|
|
end = pos + dir * length;
|
|
trace = G_FullTrace( pos, vec_zero, vec_zero, end, 30, this, MASK_PROJECTILE, "QuantumDestabilizer::Shoot" );
|
|
delta = trace.endpos - pos;
|
|
|
|
// Set the pitch of this weapon so the client can use it to flame in the right direction
|
|
dir = Vector( owner->orientation[ 0 ] );
|
|
angles = dir.toAngles();
|
|
setAngles( angles );
|
|
|
|
damg = 25;
|
|
TraceAttack( pos, trace.endpos, damg, &trace, 0, 0, 0 );
|
|
NextAttack( 0 );
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
// DESTABILIZE MODE
|
|
{
|
|
if ( trapped_sent )
|
|
{
|
|
ShootSentient(pos, dir);
|
|
ammorequired = 0;
|
|
}
|
|
else
|
|
{
|
|
SuckSentient(pos,dir);
|
|
ammorequired = 20;
|
|
}
|
|
}
|
|
NextAttack( 0.5 );
|
|
#endif
|
|
}
|
|
|
|
qboolean QuantumDestabilizer::Drop
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
#if 0
|
|
ammorequired = 20;
|
|
if ( trapped_sent )
|
|
{
|
|
if ( !ShootSentient( worldorigin, Vector( 0,0,1 ) ) )
|
|
{
|
|
// Can't shoot the sentient out, so kill it
|
|
trapped_sent->health = 0;
|
|
trapped_sent->Damage( this, owner, 1000, worldorigin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR|DAMAGE_NO_SKILL, MOD_ION_DESTRUCT, -1, -1, 1.0f );
|
|
}
|
|
}
|
|
#endif
|
|
CancelEventsOfType( EV_Quantum_EatAmmo );
|
|
CancelEventsOfType( EV_Quantum_Destruct );
|
|
return( Weapon::Drop() );
|
|
}
|