//-----------------------------------------------------------------------------
//
//  $Logfile:: /Quake 2 Engine/Sin/code/game/gibs.cpp                         $
// $Revision:: 21                                                             $
//   $Author:: Jimdose                                                        $
//     $Date:: 11/19/98 9:29p                                                 $
//
// 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/gibs.cpp                              $
// 
// 21    11/19/98 9:29p Jimdose
// gibs copy gravaxis
// 
// 20    11/09/98 1:09a Aldie
// Changed fadesplat to fade in 30 secs
// 
// 19    11/08/98 8:31p Aldie
// Added ability to not fade splats
// 
// 18    10/22/98 9:30p Aldie
// Modified gib physics a little
// 
// 17    10/07/98 11:51p Jimdose
// moved body_parts out of game structure
// 
// 16    9/22/98 5:26p Markd
// fixed small gib bug
// 
// 15    9/22/98 5:19p Markd
// Put in new consolidated gib function
// 
// 14    9/20/98 5:11p Aldie
// Added blood trail to gib constructor
// 
// 13    8/29/98 9:43p Jimdose
// Added call info to G_Trace
// 
// 12    8/27/98 9:02p Jimdose
// Changed centroid to a variable
// 
// 11    8/19/98 8:49p Aldie
// Increased gibbage velocity
// 
// 10    8/10/98 6:52p Aldie
// Changed the gib throwing code
// 
// 9     7/29/98 2:31p Aldie
// Changed health to a float
// 
// 8     7/26/98 3:58p Aldie
// Reversed a logic bug 
// 
// 7     7/25/98 8:39p Aldie
// Bloodsplat only in single player
// 
// 6     7/24/98 10:04p Aldie
// Changed the gibs layout
// 
// 5     7/23/98 6:55p Aldie
// Fun with gibs
// 
// 4     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
// 
// 3     6/30/98 12:40p Aldie
// Changed bloodsplat scale.
// 
// 2     5/27/98 5:03a Aldie
// First version of gibs
//
// DESCRIPTION:
// Gibs - nuff said

#include "gibs.h"

const char *body_parts[] = 
	{
    "gib1.def", "gibtorso.def", "gibhead.def", "gibleg.def" 
	 //"gib1.def", "gib2.def", "gibhead.def", "gibleg.def", "gibarm.def", "gibribs.def"
	};

const int num_body_parts = ( sizeof( body_parts ) / sizeof( body_parts[ 0 ] ) );

CLASS_DECLARATION( Entity, Gib, "gib" );

Event EV_ThrowGib("throwgib");

ResponseDef Gib::Responses[] =
	{
      { &EV_ThrowGib, ( Response )&Gib::Throw },
      { &EV_Touch,    ( Response )&Gib::Splat },
      { NULL, NULL }
	};

Gib::Gib
	(
	const char *name,
   qboolean blood_trail
	)

   {
   setSize("0 0 0", "0 0 0");
   setModel(name);
	setMoveType( MOVETYPE_BOUNCE );
	setSolidType( SOLID_BBOX );	
   if ( blood_trail )
      edict->s.effects |= EF_GIB;
   sprayed     = false;
   fadesplat   = true;
   }

Gib::Gib()
   {
   setSize("0 0 0", "0 0 0");
   setModel("gib1.def");
	setMoveType( MOVETYPE_BOUNCE );
	setSolidType( SOLID_BBOX );	
   edict->s.effects |= EF_GIB;
   sprayed           = false;
   fadesplat         = true;
   }

void Gib::Splat
	(
	Event *ev
	)

   {
   Vector end;

   if (deathmatch->value)
      return;
   
   if (!sv_gore->value)
      return;

   if (sprayed)
      return;

   sprayed = true;
   end = origin;
   end.z -= 1024;

   SprayBlood(origin, end, 25);

   setSolidType(SOLID_NOT);
   }

void Gib::SprayBlood
	(
	Vector start,
	Vector end,
	int damage
	)

   {
	trace_t     trace;
   float       dist;
   float       scale;
   Entity      *splat;
   Vector      norm;

   trace = G_Trace( start, vec_zero, vec_zero, end, NULL, MASK_SOLIDNONFENCE, "Gib::SprayBlood" );

	if ( HitSky( &trace ) || ( trace.ent->solid != SOLID_BSP ) )
		{
		return;
		}

   dist = ( Vector( trace.endpos ) - start ).length();
   scale = ( float )damage / ( dist * 0.3 );
   if ( scale > 0.6 )
		{
      scale = 0.6;
		}
   if ( scale < 0.02 )
		{
      return;
		}

   // Do a bloodsplat
   splat = new Entity;
	splat->setMoveType( MOVETYPE_NONE );
	splat->setSolidType( SOLID_NOT );
   splat->setModel( "sprites/bloodsplat.spr" );
	splat->edict->s.frame = G_Random( 4 );
	splat->setSize( "0 0 0", "0 0 0" );
	splat->edict->s.scale = scale * this->edict->s.scale;
   norm = trace.plane.normal;
   norm.x = -norm.x;
   norm.y = -norm.y;
   splat->angles = norm.toAngles();
   splat->angles.z = G_Random( 360 );
	splat->setAngles( splat->angles );
   splat->setOrigin( Vector( trace.endpos ) + ( Vector( trace.plane.normal ) * 0.2 ) );
	
   if ( fadesplat )
      splat->PostEvent( EV_FadeOut, 3 );
   else
      splat->PostEvent( EV_FadeOut, 30 );
   }

void Gib::ClipGibVelocity
	(
	void
	)

	{
	if (velocity[0] < -400)
		velocity[0] = -400;
	else if (velocity[0] > 400)
		velocity[0] = 400;
	if (velocity[1] < -400)
		velocity[1] = -400;
	else if (velocity[1] > 400)
		velocity[1] = 400;
	if (velocity[2] < 200)
		velocity[2] = 200;	// always some upwards
	else if (velocity[2] > 600)
		velocity[2] = 600;
}

void Gib::SetVelocity
	(
	float damage
	)

   {
   velocity[0] = 100.0 * crandom();
	velocity[1] = 100.0 * crandom();
	velocity[2] = 200.0 + 100.0 * random();
   
   avelocity = Vector( G_Random( 600 ), G_Random( 600 ), G_Random( 600 ) );
   
   if ( ( damage < -150 )  && ( G_Random() > 0.95f ) )
      velocity *= 2.0f;
   else if ( damage < -100 )
      velocity *= 1.5f;
   
   ClipGibVelocity();
   }

void Gib::Throw
	(
	Event *ev
	)

   {
   Entity *ent;

   ent = ev->GetEntity(1);    
   setOrigin(ent->centroid);
   worldorigin.copyTo(edict->s.old_origin);
   SetVelocity(ev->GetInteger(2));
   edict->s.scale = ev->GetFloat(3);
   PostEvent(EV_FadeOut, 10 + G_Random(5));
   }


void CreateGibs
   ( 
   Entity * ent, 
   float damage, 
   float scale, 
   int num, 
   const char * modelname
   )
   {
   int i;
   Gib * gib;

   assert( ent );

   if ( !ent )
      return;

   ent->RandomGlobalSound( "impact_gib" );
   for ( i = 0; i < num; i++ )
      {
      if ( modelname )
         {
         gib = new Gib( modelname );
         }
      else
         {
         gib = new Gib( body_parts[ i % num_body_parts ] );
         }
      gib->setOrigin(ent->centroid);
      gib->worldorigin.copyTo(gib->edict->s.old_origin);
      gib->SetVelocity( damage );
      gib->edict->s.scale = scale + G_Random( scale * 0.3 );
      gib->SetGravityAxis( ent->gravaxis );
      gib->PostEvent(EV_FadeOut, 10 + G_Random(5));
      }
   }
