/*
   ================================================================
   SPLITTER
   ================================================================

   Copyright (C) 1998 by 2015, Inc.
   All rights reserved.

   This source is may not be distributed and/or modified without
   expressly written permission by 2015, Inc.
 */


#include "g_local.h"
#include "actor.h"
#include "gibs.h"
#include "splitter.h"
#include "flamethrower.h"


CLASS_DECLARATION( Actor, Splitter, "monster_splitter" );

Event EV_Splitter_SpawnBug( "spawnbug" );

ResponseDef Splitter::Responses[] =
{
	{ &EV_Killed,   ( Response )Splitter::KilledEvent },
	{ &EV_Splitter_SpawnBug,    ( Response )Splitter::SpawnBugEvent },
	{ NULL, NULL }
};



////////////////////////////////////////////////
//
// SpawnBugEvent
//
////////////////////////////////////////////////

void Splitter::SpawnBugEvent
// Spawns a bug actor and throws it from the splitter
    ( Event *ev )
{
	Vector pos;
	char temp[128];

	// Make the splitter not-solid, so the bug doesn't get caught in him
	setSolidType( SOLID_NOT );

	// Find the appropriate bone in the splitter for spawning the bug
	// at (currently disabled since there is not bone)
	pos = worldorigin;
	pos.z += 20;

	// Spawn lots of blood and shit
	// Well, not shit - not literally, anyhow.

	//Creategibs arguments:
	//1 - entity where they are spawned from
	//2 - damage done which translates to speed to throw them at
	//3 - maximum size of gibs to be created
	//4 - number of gibs
	//5 - optional model to use
	//From another spot in the code:  CreateGibs( this, health, gibsize, numgibs );
	CreateGibs( this, -50, 0.8, 5, "gib1.def" );
	CreateGibs( this, -200, 0.3, 5, "gib2.def" );


	// Clear the spawn args
	G_InitSpawnArguments();

	sprintf( temp, "%f %f %f", (float)pos.x, (float)pos.y, (float)pos.z );
	G_SetSpawnArg( "origin", temp );
	sprintf( temp, "%f", (float)angles[YAW] );
	G_SetSpawnArg( "angle", temp );
	G_SetSpawnArg( "model", "bug.def" );
	G_SetSpawnArg( "targetname", TargetName() );    // Gives the splitter's targetname to the bug
	G_SetSpawnArg( "attackmode", "2" );

	G_CallSpawn();
	// Clear the spawn args
	G_InitSpawnArguments();

}


////////////////////////////////////////////////
// KilledEvent
////////////////////////////////////////////////

void Splitter::KilledEvent
// Based on Actor::Killed
// Since WarT had already altered Actor::Killed, I've put my alterations to that
// in #### markings.

    ( Event *ev )
{
	const char  *name;
	Entity      *ent;
	int num;
	Entity      *attacker;
	Entity      *inflictor;
	Vector dir;
	Event           *event;
	int i;
	str dname;
	int meansofdeath;
	int j;

	CheckWater();
	StopAnimating();
	CancelPendingEvents();

	// don't allow them to fly, think, or swim anymore
	flags &= ~( FL_PRETHINK | FL_SWIM | FL_FLY );

	deadflag = DEAD_DYING;
	takedamage = DAMAGE_YES;
	groundentity = NULL;

	attacker    = ev->GetEntity( 1 );
	inflictor = ev->GetEntity( 3 );
	meansofdeath = ev->GetInteger( 5 );

	// Double all the armor
	DoubleArmor();

	SetVariable( "other", ev->GetEntity( 1 ) );
	if ( !DoAction( "killed" ) && actorthread )
	{
		actorthread->ProcessEvent( EV_ScriptThread_End );
	}


	// Turn off dlight and shadow
	edict->s.renderfx &= ~( RF_DLIGHT|RF_XFLIP );

	//
	// kill the killtargets
	//
	// added extended targeting stuff
	name = KillTarget();
	for(j = 0; j < 2; j++)
	{
		switch(j)
		{
		case 0:
			name = KillTarget();
			break;
		case 1:
			name = KillTarget2();
			break;
		}

		if ( name && strcmp( name, "" ) )
		{
			num = 0;
			do
			{
				num = G_FindTarget( num, name );
				if ( !num )
				{
					break;
				}

				ent = G_GetEntity( num );
				ent->PostEvent( EV_Remove, 0 );
			} while ( 1 );
		}
	}

	//
	// fire targets
	//
	// added extended targeting stuff
	for(j = 0; j < 4; j++)
	{
		switch(j)
		{
		case 0:
			name = Target();
			break;
		case 1:
			name = Target2();
			break;
		case 2:
			name = Target3();
			break;
		case 3:
			name = Target4();
			break;
		}

		if ( name && strcmp( name, "" ) )
		{
			num = 0;
			do
			{
				num = G_FindTarget( num, name );
				if ( !num )
				{
					break;
				}

				ent = G_GetEntity( num );

				event = new Event( EV_Activate );
				event->AddEntity( attacker );
				ent->ProcessEvent( event );
			} while ( 1 );
		}
	}

	//
	// see if we have a kill_thread
	//
	if ( kill_thread.length() > 1 )
	{
		ScriptThread * thread;

		//
		// create the thread, but don't start it yet
		//
		thread = ExecuteThread( kill_thread, false );
		if ( thread )
		{
			ProcessScript( thread, NULL );
		}
		else
		{
			warning( "Killed", "could not process kill_thread" );
		}
	}

	if ( DoGib( meansofdeath, inflictor ) )
	{
		deathgib = true;
	}

	// skin darkening for death from flames
	if(inflictor->isSubclassOf( ThrowerFlame ))
	{
		edict->s.renderfx |= RF_LIGHTOFFSET;
		edict->s.lightofs = -127;

		CancelEventsOfType( EV_Sentient_HurtFlame );
		edict->s.effects  |= EF_FLAMES;
	}
	else
	{
		// turn off the actor's heat signature
		edict->s.effects &= ~EF_WARM;
	}

	if ( currentWeapon )
	{
		DropWeapon( currentWeapon );
	}

	animOverride = false;

	//
	// determine death animation
	//
	if ( !strncmp( animname.c_str(), "crouch", 6 ) )
	{
		dname = "crouch_";
	}

	if ( !strncmp( animname.c_str(), "live_split", 10 ) )
	{
		dname = "live_split_";
	}
	else if ( !strncmp( animname.c_str(), "dead", 4 ) )
	{
		dname = "dead_split_";
	}
	else if ( deathgib )
	{
		str location;

		location = ev->GetString( 4 );

		// Check for location first otherwise randomize
		if ( location == "torso_upper" )
			dname += str( "gibdeath_upper" );
		else if ( location == "torso_lower" )
			dname += str( "gibdeath_lower" );
		else if ( strstr( location.c_str(), "leg" ) )
			dname += str( "gibdeath_lower" );
		else if ( strstr( location.c_str(), "arm" ) )
			dname += str( "gibdeath_upper" );
		else if ( strstr( location.c_str(), "head" ) )
			dname += str( "gibdeath_upper" );
		else if ( G_Random() > 0.5 )
			dname += str( "gibdeath_upper" );
		else
			dname += str( "gibdeath_lower" );
	}
	else
	{
		dname += str( "death_" ) + str( ev->GetString( 4 ) );
	}

	i = gi.Anim_Random( edict->s.modelindex, dname.c_str() );

	if ( ( i == -1 ) && !strncmp( animname.c_str(), "crouch", 6 ) )
	{
		dname = "crouch_death";
		i = gi.Anim_Random( edict->s.modelindex, dname.c_str() );
	}

	if ( ( i == -1 ) && !strncmp( animname.c_str(), "live_split", 10 ) )
	{
		dname = "live_split_death";
		i = gi.Anim_Random( edict->s.modelindex, dname.c_str() );
	}
	if ( ( i == -1 ) && !strncmp( animname.c_str(), "dead", 4 ) )
	{
		dname = "dead_split_death";
		i = gi.Anim_Random( edict->s.modelindex, dname.c_str() );
	}

	if ( i == -1 )
	{
		dname = "death";
	}
	if ( ( i != -1 ) &&  ( !strncmp( dname.c_str(), "gibdeath", 7 ) ) )
	{
		Event *ev1;

		ev1 = new Event( EV_Gib );
		ev1->AddInteger( 1 );
		ProcessEvent( ev1 );
	}
	if ( attacker )
	{
		str location;
		float damage;

		damage = ev->GetFloat( 2 );
		location = ev->GetString( 4 );

		event = new Event( EV_GotKill );
		event->AddEntity( this );
		event->AddInteger( damage );
		event->AddEntity( inflictor );
		event->AddString( location );
		event->AddInteger( meansofdeath );
		event->AddInteger( deathgib );
		attacker->ProcessEvent( event );
	}

	SetAnim( dname.c_str(), EV_Actor_Dead );

	// Call changeanim immediatly since we're no longer calling prethink
	ChangeAnim();

	//
	// moved this here so guys would not be solid right away
	//
	edict->svflags |= SVF_DEADMONSTER;
	edict->clipmask = MASK_DEADSOLID;

	angles.x = 0;
	angles.z = 0;
	setAngles( angles );
}




Splitter::Splitter()
{
	setModel( "splitter.def" );
	modelIndex( "bug.def" );
}

/****************************************************************************
   // for bug
   Jump2 Class Definition

****************************************************************************/

CLASS_DECLARATION( Jump, Jump2, NULL );

ResponseDef Jump2::Responses[] =
{
	{ NULL, NULL }
};

void Jump2::Begin( Actor &self )
{
	float traveltime;
	float dist;
	Vector goaldir,newgoal;

	if ( anim.length() )
	{
		self.SetAnim( anim );
	}
// making it jump no more than 500 units
	goaldir = goal - self.worldorigin;
	dist = goaldir.length();
	if (dist > 500)
	{
		goaldir.normalize();
		goaldir *= 500;
	}
	newgoal = goaldir + self.worldorigin;

	traveltime = self.JumpTo( newgoal, speed );
	endtime = traveltime + level.time;

	self.last_jump_time = endtime;

	state = 0;
}
