//-----------------------------------------------------------------------------
//
//  $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() );
   }
