//-----------------------------------------------------------------------------
//
//  $Logfile:: /Quake 2 Engine/Sin/code/game/scriptslave.cpp                  $
// $Revision:: 80                                                             $
//   $Author:: Markd                                                          $
//     $Date:: 10/28/98 8:37p                                                 $
//
// Copyright (C) 1997 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/scriptslave.cpp                       $
//
// 80    10/28/98 8:37p Markd
// Added notshootable functionality
//
// 79    10/27/98 9:15p Jimdose
// overrode bind and unbind events
//
// 78    10/25/98 4:22a Markd
// Changed explode command for scriptslaves
//
// 77    10/24/98 2:08p Aldie
// Added func_volumetric
//
// 76    10/24/98 12:42a Markd
// changed origins to worldorigins where appropriate
//
// 75    10/23/98 10:04p Markd
// Added explode event
//
// 74    10/19/98 12:07a Jimdose
// made all code use fast checks for inheritance (no text lookups when
// possible)
// isSubclassOf no longer requires ::_classinfo()
//
// 73    10/14/98 10:18p Jimdose
// made DoMove not return if event's thread was NULL
//
// 72    9/23/98 11:00p Markd
// put in some garbage collection on stuff that wasn't freed up
//
// 71    9/23/98 9:28p Jimdose
// Made thread callback functions clear their labels if the thread is NULL.
// Also removed assertion from callback functions
//
// 70    9/22/98 5:20p Markd
// Put in new consolidated gib function
//
// 69    9/22/98 3:21p Markd
// put in parentmode lockout for blood and gibs
//
// 68    8/22/98 9:33p Markd
// Put in code which would ensure that threads are valid when gotten from the
// event
//
// 67    8/21/98 3:47p Markd
// Added new rotation commands
//
// 66    8/21/98 1:45a Markd
// Added RotateDownTo, RotateUpTo and RotateTo
//
// 65    8/20/98 4:31p Markd
// Added vector support to moveto and jumpto
//
// 64    8/17/98 7:31p Jimdose
// DoMove only sets moveThread if the specified thread is waiting for that
// entity
//
// 63    7/31/98 4:21p Jimdose
// Made events statically created instead of dynamic
//
// 62    7/24/98 7:37p Aldie
// Added feather gibs
//
// 61    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
//
// 60    7/22/98 3:48p Jimdose
// Changed damage to an event function.  Fixed the slaves not responding to
// damage
//
// 59    7/22/98 12:52p Markd
// tweaked the waitfor on Following Path stuff
//
// 58    7/21/98 10:05p Markd
// Added starttime to followpath
//
// 57    7/21/98 5:32p Jimdose
// DoMove now posts a move done event if no commands are waiting so that any
// waitFor's that are called after a slave has finished it's move won't be
// stuck forever
//
// 56    7/21/98 4:23p Aldie
// Make icons work for locks
//
// 55    7/21/98 1:10p Aldie
// Added meansofdeath to obituaries
//
// 54    7/19/98 4:25p Markd
// Added "other" and "key" support to usethread
//
// 53    7/19/98 3:42p Markd
// Added ondamage variables
//
// 52    7/18/98 3:53p Markd
// Added key support to scriptslave
//
// 51    7/11/98 6:31p Markd
// removed valid orientation, simplified code
//
// 50    7/10/98 1:55p Markd
// when checking for end of spline, had to do a > rather than a >=
//
// 49    7/10/98 1:11p Markd
// Added some more functionality to spline based movement
//
// 48    7/09/98 11:53p Markd
// Added non-orientation support for spline_paths
//
// 47    7/09/98 9:39p Jimdose
// Removed RF_CONSOLE
//
// 46    7/08/98 8:54p Markd
// maybe I didn't need to invert pitch!
//
// 45    7/08/98 12:55p Markd
// forgot to invert pitch on spline based stuff
//
// 44    7/08/98 12:42p Markd
// Added followpath and resumepath and followingpath for spline based movement
//
// 43    6/18/98 8:47p Jimdose
// Added better event error handling
// Added source info to events
//
// 42    6/11/98 11:52a Aldie
// Updated scriptslave damage function to use all the same parms as the
// entity::damage function.
//
// 41    6/10/98 2:10p Aldie
// Updated damage function.
//
// 40    5/24/98 8:46p Jimdose
// Made a lot of functions more str-friendly.
// Got rid of a lot of char * based strings
// Cleaned up get spawn arg functions and sound functions
// sound functions now use consistant syntax
//
// 39    5/24/98 4:48p Jimdose
// Made char *'s const
//
// 38    5/24/98 2:46p Markd
// Made char *'s into const char *'s
//
// 37    5/23/98 4:48p Aldie
// Removed RF_CONSOLE from script object
//
// 36    5/20/98 4:32p Markd
// bullet proofed thread code and made sure that thread variable was non-null
//
// 35    5/19/98 9:52p Markd
// added not_damage flag to objects
//
// 34    5/03/98 4:37p Jimdose
// Changed Vector class
//
// 33    5/01/98 5:08p Jimdose
// TriggerEvent now specifies world as the activator
//
// 32    4/29/98 7:13p Jimdose
// forgot an else. :(
//
// 31    4/29/98 6:34p Jimdose
// Made ScriptSlave use SOLID_NOT when there's a NULL model
//
// 30    4/29/98 6:30p Jimdose
// Added ScriptOrigin
//
// 29    4/25/98 5:09p Markd
// Added up and down support for angles
//
// 28    4/20/98 11:01a Markd
// Fixed client side prediction of non-solid shootables
//
// 27    4/18/98 7:30p Markd
// Made func_scriptmodel not have any dimension
//
// 26    4/18/98 6:10p Aldie
// Added RF_CONSOLE to script objects so users can render consoles on them.
//
// 25    4/09/98 1:40p Markd
// Added in CONTENTS_SHOOTABLE stuff
//
// 24    4/08/98 4:20p Jimdose
// Added NOT_SOLID spawnflag
//
// 23    4/07/98 9:34p Jimdose
// Scriptobjects respond to damage
//
// 22    4/07/98 8:00p Markd
// removed defhandle, changed all SINMDL calls to modelindex calls, removed
// SINMDL prefix
//
// 21    4/06/98 3:55p Jimdose
// Since RF_FRAMELERP is now cleared out every frame, ClearLerp was redundant
//
// 20    4/05/98 1:59a Jimdose
// Made Jumpto prevent lerping of the models position
// Added ScriptModel for amodel-based script objects
//
// 19    3/31/98 2:27p Jimdose
// Cleared out the angles at start
//
// 18    3/30/98 8:09p Jimdose
// Made forward and backward use the start angle
//
// 17    3/24/98 4:58p Jimdose
// Added NewOrders to indicate when the slave should update NewAngles
// Fixed typo related  bugs in touch, block, use, damage callback functions
//
// 16    3/23/98 1:31p Jimdose
// Revamped event and command system
//
// 15    3/02/98 8:49p Jimdose
// Changed the classid parameter of CLASS_DECLARATION to a quoted string so
// that you could have a NULL classid.
//
// 14    2/21/98 1:11p Jimdose
// Fixed bug where EVENT_SCRIPTSLAVE_MOVEDONE was allowing the event to pass to
// the superclass
//
// 13    2/18/98 8:07p Jimdose
// Changed pointers to scriptMaster to entity numbers
// Changed direct calls to the master into events
//
// 12    2/17/98 8:34p Jimdose
// Fixed NULL pointer problem in the onTouch, etc, functions
//
// 11    2/17/98 7:09p Jimdose
// no longer pass script into interpretCommand
// added error handling for invalid labels
//
// 10    2/16/98 2:15p Jimdose
// Added script commands rotateX, rotateY, and rotateZ for continual arbitrary
// rotation
//
// 9     2/06/98 5:38p Jimdose
// Added check for null jumpto in onTouch, onBlock, onDamage, etc.
//
// 8     2/03/98 10:44a Jimdose
// Updated to work with Quake 2 engine
//
// 6     10/28/97 4:15p Jimdose
// Removed CommandsWaiting.
// Moved "bind" and "unBind" commands into Entity
// Made DoMove be called when "processCommands" message is sent.
//
// 5     10/27/97 3:29p Jimdose
// Removed dependency on quakedef.h
//
// 4     10/22/97 12:25p Jimdose
// Fixed bug where slave wouldn't damage other entities when they blocked it.
//
// 3     9/26/97 5:23p Jimdose
// Added standard Ritual headers
//
// DESCRIPTION:
// Standard scripted objects.  Controlled by ScriptThread.  These objects
// are bmodel objects created in the editor and controlled by an external
// text based script.  Commands are interpretted on by one and executed
// upon a signal from the script master.  The base script object can
// perform several different relative and specific rotations and translations
// and can cause other parts of the script to be executed when touched, damaged,
// touched, or used.
//

#include "g_local.h"
#include "class.h"
#include "mover.h"
#include "scriptmaster.h"
#include "scriptslave.h"
#include "sentient.h"
#include "item.h"
#include "gibs.h"
#include "explosion.h"

/*****************************************************************************/
/*SINED func_scriptobject (0 .5 .8) ? NOT_SOLID

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

CLASS_DECLARATION( Mover, ScriptSlave, "func_scriptobject" );

Event EV_ScriptSlave_DoMove( "processCommands" );
Event EV_ScriptSlave_NewOrders( "newOrders" );
Event EV_ScriptSlave_Angles( "angles" );
Event EV_ScriptSlave_Trigger( "trigger" );
Event EV_ScriptSlave_Next( "next" );
Event EV_ScriptSlave_JumpTo( "jumpto" );
Event EV_ScriptSlave_MoveTo( "moveto" );
Event EV_ScriptSlave_Speed( "speed" );
Event EV_ScriptSlave_Time( "time" );
Event EV_ScriptSlave_MoveUp( "moveUp" );
Event EV_ScriptSlave_MoveDown( "moveDown" );
Event EV_ScriptSlave_MoveNorth( "moveNorth" );
Event EV_ScriptSlave_MoveSouth( "moveSouth" );
Event EV_ScriptSlave_MoveEast( "moveEast" );
Event EV_ScriptSlave_MoveWest( "moveWest" );
Event EV_ScriptSlave_MoveForward( "moveForward" );
Event EV_ScriptSlave_MoveBackward( "moveBackward" );
Event EV_ScriptSlave_MoveLeft( "moveLeft" );
Event EV_ScriptSlave_MoveRight( "moveRight" );
Event EV_ScriptSlave_RotateXDownTo( "rotateXdownto" );
Event EV_ScriptSlave_RotateYDownTo( "rotateYdownto" );
Event EV_ScriptSlave_RotateZDownTo( "rotateZdownto" );
Event EV_ScriptSlave_RotateAxisDownTo( "rotateaxisdownto" );
Event EV_ScriptSlave_RotateXUpTo( "rotateXupto" );
Event EV_ScriptSlave_RotateYUpTo( "rotateYupto" );
Event EV_ScriptSlave_RotateZUpTo( "rotateZupto" );
Event EV_ScriptSlave_RotateAxisUpTo( "rotateaxisupto" );
Event EV_ScriptSlave_RotateXDown( "rotateXdown" );
Event EV_ScriptSlave_RotateYDown( "rotateYdown" );
Event EV_ScriptSlave_RotateZDown( "rotateZdown" );
Event EV_ScriptSlave_RotateAxisDown( "rotateaxisdown" );
Event EV_ScriptSlave_RotateXUp( "rotateXup" );
Event EV_ScriptSlave_RotateYUp( "rotateYup" );
Event EV_ScriptSlave_RotateZUp( "rotateZup" );
Event EV_ScriptSlave_RotateAxisUp( "rotateaxisup" );
Event EV_ScriptSlave_RotateX( "rotateX" );
Event EV_ScriptSlave_RotateY( "rotateY" );
Event EV_ScriptSlave_RotateZ( "rotateZ" );
Event EV_ScriptSlave_RotateAxis( "rotateaxis" );
Event EV_ScriptSlave_RotateDownTo( "rotatedownto" );
Event EV_ScriptSlave_RotateUpTo( "rotateupto" );
Event EV_ScriptSlave_RotateTo( "rotateto" );
Event EV_ScriptSlave_OnTouch( "ontouch" );
Event EV_ScriptSlave_NoTouch( "notouch" );
Event EV_ScriptSlave_OnUse( "onuse" );
Event EV_ScriptSlave_NoUse( "nouse" );
Event EV_ScriptSlave_OnBlock( "onblock" );
Event EV_ScriptSlave_NoBlock( "noblock" );
Event EV_ScriptSlave_OnTrigger( "ontrigger" );
Event EV_ScriptSlave_NoTrigger( "notrigger" );
Event EV_ScriptSlave_OnDamage( "ondamage" );
Event EV_ScriptSlave_NoDamage( "nodamage" );
Event EV_ScriptSlave_SetDamage( "setdamage" );
Event EV_ScriptSlave_FollowPath( "followpath" );
Event EV_ScriptSlave_EndPath( "endpath" );
Event EV_ScriptSlave_MoveDone( "scriptslave_movedone" );
Event EV_ScriptSlave_FollowingPath( "scriptslave_followingpath" );
Event EV_ScriptSlave_Explode( "explode" );
Event EV_ScriptSlave_NotShootable( "notshootable" );

ResponseDef ScriptSlave::Responses[] =
{
	{ &EV_Bind, ( Response )& ScriptSlave::BindEvent },
	{ &EV_Unbind, ( Response )& ScriptSlave::EventUnbind },
	{ &EV_ScriptSlave_DoMove, ( Response )& ScriptSlave::DoMove },
	{ &EV_ScriptSlave_NewOrders, ( Response )& ScriptSlave::NewOrders },
	{ &EV_ScriptSlave_Angles, ( Response )& ScriptSlave::SetAnglesEvent },
	{ &EV_ScriptSlave_Trigger, ( Response )& ScriptSlave::TriggerEvent },
	{ &EV_ScriptSlave_Next, ( Response )& ScriptSlave::GotoNextWaypoint },
	{ &EV_ScriptSlave_JumpTo, ( Response )& ScriptSlave::JumpTo },
	{ &EV_ScriptSlave_MoveTo, ( Response )& ScriptSlave::MoveToEvent },
	{ &EV_ScriptSlave_Speed, ( Response )& ScriptSlave::SetSpeed },
	{ &EV_ScriptSlave_Time, ( Response )& ScriptSlave::SetTime },
	{ &EV_ScriptSlave_MoveUp, ( Response )& ScriptSlave::MoveUp },
	{ &EV_ScriptSlave_MoveDown, ( Response )& ScriptSlave::MoveDown },
	{ &EV_ScriptSlave_MoveNorth, ( Response )& ScriptSlave::MoveNorth },
	{ &EV_ScriptSlave_MoveSouth, ( Response )& ScriptSlave::MoveSouth },
	{ &EV_ScriptSlave_MoveEast, ( Response )& ScriptSlave::MoveEast },
	{ &EV_ScriptSlave_MoveWest, ( Response )& ScriptSlave::MoveWest },
	{ &EV_ScriptSlave_MoveForward, ( Response )& ScriptSlave::MoveForward },
	{ &EV_ScriptSlave_MoveBackward, ( Response )& ScriptSlave::MoveBackward },
	{ &EV_ScriptSlave_MoveLeft, ( Response )& ScriptSlave::MoveLeft },
	{ &EV_ScriptSlave_MoveRight, ( Response )& ScriptSlave::MoveRight },
	{ &EV_ScriptSlave_RotateXDownTo, ( Response )& ScriptSlave::RotateXdownto },
	{ &EV_ScriptSlave_RotateYDownTo, ( Response )& ScriptSlave::RotateYdownto },
	{ &EV_ScriptSlave_RotateZDownTo, ( Response )& ScriptSlave::RotateZdownto },
	{ &EV_ScriptSlave_RotateXUpTo, ( Response )& ScriptSlave::RotateXupto },
	{ &EV_ScriptSlave_RotateYUpTo, ( Response )& ScriptSlave::RotateYupto },
	{ &EV_ScriptSlave_RotateZUpTo, ( Response )& ScriptSlave::RotateZupto },
	{ &EV_ScriptSlave_RotateXDown, ( Response )& ScriptSlave::RotateXdown },
	{ &EV_ScriptSlave_RotateYDown, ( Response )& ScriptSlave::RotateYdown },
	{ &EV_ScriptSlave_RotateZDown, ( Response )& ScriptSlave::RotateZdown },
	{ &EV_ScriptSlave_RotateXUp, ( Response )& ScriptSlave::RotateXup },
	{ &EV_ScriptSlave_RotateYUp, ( Response )& ScriptSlave::RotateYup },
	{ &EV_ScriptSlave_RotateZUp, ( Response )& ScriptSlave::RotateZup },
	{ &EV_ScriptSlave_RotateX, ( Response )& ScriptSlave::RotateX },
	{ &EV_ScriptSlave_RotateY, ( Response )& ScriptSlave::RotateY },
	{ &EV_ScriptSlave_RotateZ, ( Response )& ScriptSlave::RotateZ },
	{ &EV_ScriptSlave_RotateAxisDownTo, ( Response )& ScriptSlave::RotateAxisdownto },
	{ &EV_ScriptSlave_RotateAxisUpTo, ( Response )& ScriptSlave::RotateAxisupto },
	{ &EV_ScriptSlave_RotateAxisDown, ( Response )& ScriptSlave::RotateAxisdown },
	{ &EV_ScriptSlave_RotateAxisUp, ( Response )& ScriptSlave::RotateAxisup },
	{ &EV_ScriptSlave_RotateAxis, ( Response )& ScriptSlave::RotateZ },
	{ &EV_ScriptSlave_OnTouch, ( Response )& ScriptSlave::OnTouch },
	{ &EV_ScriptSlave_NoTouch, ( Response )& ScriptSlave::NoTouch },
	{ &EV_ScriptSlave_OnUse, ( Response )& ScriptSlave::OnUse },
	{ &EV_ScriptSlave_NoUse, ( Response )& ScriptSlave::NoUse },
	{ &EV_ScriptSlave_OnBlock, ( Response )& ScriptSlave::OnBlock },
	{ &EV_ScriptSlave_NoBlock, ( Response )& ScriptSlave::NoBlock },
	{ &EV_ScriptSlave_OnTrigger, ( Response )& ScriptSlave::OnTrigger },
	{ &EV_ScriptSlave_NoTrigger, ( Response )& ScriptSlave::NoTrigger },
	{ &EV_ScriptSlave_OnDamage, ( Response )& ScriptSlave::OnDamage },
	{ &EV_ScriptSlave_NoDamage, ( Response )& ScriptSlave::NoDamage },
	{ &EV_ScriptSlave_SetDamage, ( Response )& ScriptSlave::SetDamage },
	{ &EV_ScriptSlave_FollowPath, ( Response )& ScriptSlave::FollowPath },
	{ &EV_ScriptSlave_EndPath, ( Response )& ScriptSlave::EndPath },
	{ &EV_ScriptSlave_FollowingPath, ( Response )& ScriptSlave::FollowingPath },
	{ &EV_Touch, ( Response )& ScriptSlave::TouchFunc },
	{ &EV_Blocked, ( Response )& ScriptSlave::BlockFunc },
	{ &EV_Activate, ( Response )& ScriptSlave::TriggerFunc },
	{ &EV_Use, ( Response )& ScriptSlave::UseFunc },
	{ &EV_ScriptSlave_MoveDone, ( Response )& ScriptSlave::MoveEnd },
	{ &EV_Damage, ( Response )& ScriptSlave::DamageFunc },
	{ &EV_ScriptSlave_RotateDownTo, ( Response )& ScriptSlave::Rotatedownto },
	{ &EV_ScriptSlave_RotateUpTo, ( Response )& ScriptSlave::Rotateupto },
	{ &EV_ScriptSlave_RotateTo, ( Response )& ScriptSlave::Rotateto },
	{ &EV_ScriptSlave_Explode, ( Response )& ScriptSlave::Explode },
	{ &EV_ScriptSlave_NotShootable, ( Response )& ScriptSlave::NotShootable },

	{ NULL, NULL }
};

ScriptSlave::ScriptSlave()
{
	float angle;
	const char* m;

	showModel();

	speed = G_GetFloatArg( "speed", 100 );

	angle = G_GetFloatArg( "angle" );
	if( angle == -1 )
	{
		ForwardDir = Vector( 0, 0, 90 );
	}
	else if( angle == -2 )
	{
		ForwardDir = Vector( 0, 0, -90 );
	}
	else
	{
		ForwardDir = Vector( 0, angle, 0 );
	}

	setAngles( vec_zero );

	takedamage          = DAMAGE_YES;
	waypoint                = NULL;
	NewAngles           = angles;
	NewPos              = origin;
	traveltime          = 0;
	commandswaiting = false;
	movethread          = NULL;
	touchthread         = NULL;
	blockthread         = NULL;
	damagethread        = NULL;
	triggerthread       = NULL;
	usethread           = NULL;
	splinePath        = NULL;
	splineangles      = false;

	dmg                 = G_GetIntArg( "dmg", 2 );
	attack_finished = 0;

	setMoveType( MOVETYPE_PUSH );

	m = G_GetSpawnArg( "model" );
	if( !edict->s.modelindex )
	{
		setSolidType( SOLID_NOT );
	}
	else if( spawnflags & 1 )
	{
		// if it isn't solid, lets still make it shootable
		edict->svflags |= SVF_SHOOTABLE;
		setSolidType( SOLID_BBOX );
		setOrigin( origin );
	}
	else if( !m || strstr( m, ".def" ) )
	{
		setSolidType( SOLID_BBOX );
	}
	else
	{
		setSolidType( SOLID_BSP );
	}

	edict->s.effects |= EF_SMOOTHANGLES;
}

ScriptSlave::~ScriptSlave()
{
	if( splinePath )
	{
		delete splinePath;
		splinePath = NULL;
	}
}

void ScriptSlave::NewOrders( Event* ev )
{
	// make sure position and angles are current
	NewAngles = angles;
	NewPos = origin;
}

void ScriptSlave::BindEvent( Event* ev )
{
	Entity* ent;

	ent = ev->GetEntity( 1 );
	if( ent )
	{
		bind( ent );
	}

	// make sure position and angles are current
	NewAngles = angles;
	NewPos = origin;
}

void ScriptSlave::EventUnbind( Event* ev )
{
	unbind();

	// make sure position and angles are current
	NewAngles = angles;
	NewPos = origin;
}

void ScriptSlave::DoMove( Event* ev )
{
	float dist;
	ScriptThread* thread;
	Event* event;

	thread = ev->GetThread();
	assert( thread );
	if( thread && thread->WaitingFor( this ) )
	{
		if( movethread && ( movethread != thread ) )
		{
			// warn the user
			ev->Error( "Overriding previous move commands for '%s'\n", TargetName() );

			// Yeah, we're not REALLY done, but we tell our old thread
			// that we are so that it doesn't wait forever
			event = new Event( EV_MoveDone );
			event->AddEntity( this );
			movethread->ProcessEvent( event );
		}

		movethread = thread;
	}

	if( commandswaiting )
	{
		if( splinePath )
		{
			PostEvent( EV_ScriptSlave_FollowingPath, 0 );
		}
		else
		{
			if( traveltime == 0 )
			{
				dist = Vector( NewPos - origin ).length();
				traveltime = dist / speed;
			}

			LinearInterpolate( NewPos, NewAngles, traveltime, EV_ScriptSlave_MoveDone );
		}

		commandswaiting = false;
	}
	else if( movethread && ( movethread == thread ) )
	{
		// No commands, so tell the master that we're done
		PostEvent( EV_ScriptSlave_MoveDone, 0 );
	}
}

void ScriptSlave::MoveEnd( Event* ev )
{
	Event* event;

	commandswaiting = false;
	NewAngles = angles;
	NewPos = origin;

	if( movethread )
	{
		event = new Event( EV_MoveDone );
		event->AddEntity( this );
		movethread->ProcessEvent( event );
		movethread = NULL;
	}
}

void ScriptSlave::SetAnglesEvent( Event* ev )
{
	commandswaiting = true;
	angles = ev->GetVector( 1 );
	NewAngles = angles;
}

void ScriptSlave::TriggerEvent( Event* ev )
{
	Entity* ent;
	Event*  e;

	ent = ev->GetEntity( 1 );
	if( ent )
	{
		SetTarget( ent->TargetName() );

		e = new Event( EV_Trigger_ActivateTargets );
		//fixme
		//get "other"
		e->AddEntity( world );
		ProcessEvent( e );
	}
}

void ScriptSlave::GotoNextWaypoint( Event* ev )
{
	int ent;

	commandswaiting = true;

	if( !waypoint )
	{
		ev->Error( "%s is currently not at a waypoint", TargetName() );
		return;
	}

	ent = G_FindTarget( 0, waypoint->Target() );
	if( !ent )
	{
		ev->Error( "%s could not find waypoint %s", TargetName(), waypoint->Target() );
		return;
	}

	waypoint = ( Waypoint* )G_GetEntity( ent );
	if( waypoint )
	{
		NewPos = waypoint->worldorigin;
	}
}

void ScriptSlave::JumpTo( Event* ev )
{
	Entity* part;

	//
	// see if it is a vector
	//
	if( ev->IsVectorAt( 1 ) )
	{
		NewPos = ev->GetVector( 1 );
		if( bindmaster )
		{
			origin = bindmaster->getLocalVector( NewPos - bindmaster->worldorigin );
		}
		else
		{
			origin = NewPos;
		}

		for( part = this; part; part = part->teamchain )
		{
			part->setOrigin( part->origin );
			part->worldorigin.copyTo( part->edict->s.old_origin );
			part->edict->s.renderfx |= RF_FRAMELERP;
		}
	}
	else
	{
		waypoint = ( Waypoint* )ev->GetEntity( 1 );
		if( waypoint )
		{
			NewPos = waypoint->origin;
			if( bindmaster )
			{
				origin = bindmaster->getLocalVector( NewPos - bindmaster->worldorigin );
			}
			else
			{
				origin = NewPos;
			}

			for( part = this; part; part = part->teamchain )
			{
				part->setOrigin( part->origin );
				part->worldorigin.copyTo( part->edict->s.old_origin );
				part->edict->s.renderfx |= RF_FRAMELERP;
			}
		}
	}
}

void ScriptSlave::MoveToEvent( Event* ev )
{
	commandswaiting = true;

	//
	// see if it is a vector
	//
	if( ev->IsVectorAt( 1 ) )
	{
		NewPos = ev->GetVector( 1 );
	}
	else
	{
		waypoint = ( Waypoint* )ev->GetEntity( 1 );
		if( waypoint )
		{
			NewPos = waypoint->worldorigin;
		}
	}
}

void ScriptSlave::SetSpeed( Event* ev )
{
	speed = ev->GetFloat( 1 );
	traveltime = 0;
}

void ScriptSlave::SetTime( Event* ev )
{
	traveltime = ev->GetFloat( 1 );
}

// Relative move commands

void ScriptSlave::MoveUp( Event* ev )
{
	commandswaiting = true;
	NewPos[ 2 ] += ev->GetDouble( 1 );
}

void ScriptSlave::MoveDown( Event* ev )
{
	commandswaiting = true;
	NewPos[ 2 ] -= ev->GetDouble( 1 );
}

void ScriptSlave::MoveNorth( Event* ev )
{
	commandswaiting = true;
	NewPos[ 1 ] += ev->GetDouble( 1 );
}

void ScriptSlave::MoveSouth( Event* ev )
{
	commandswaiting = true;
	NewPos[ 1 ] -= ev->GetDouble( 1 );
}

void ScriptSlave::MoveEast( Event* ev )
{
	commandswaiting = true;
	NewPos[ 0 ] += ev->GetDouble( 1 );
}

void ScriptSlave::MoveWest( Event* ev )
{
	commandswaiting = true;
	NewPos[ 0 ] -= ev->GetDouble( 1 );
}

void ScriptSlave::MoveForward( Event* ev )
{
	Vector v;
	Vector t;

	commandswaiting = true;

	t = NewAngles + ForwardDir;
	t.AngleVectors( &v, NULL, NULL );

	NewPos += v * ev->GetDouble( 1 );
}

void ScriptSlave::MoveBackward( Event* ev )
{
	Vector v;
	Vector t;

	commandswaiting = true;

	t = NewAngles + ForwardDir;
	t.AngleVectors( &v, NULL, NULL );

	NewPos -= v * ev->GetDouble( 1 );
}

void ScriptSlave::MoveLeft( Event* ev )
{
	Vector v;
	Vector t;

	commandswaiting = true;

	t = NewAngles + ForwardDir;
	t.AngleVectors( NULL, &v, NULL );

	NewPos -= v * ev->GetDouble( 1 );
}

void ScriptSlave::MoveRight( Event* ev )
{
	Vector t;
	Vector v;

	commandswaiting = true;

	t = NewAngles + ForwardDir;
	t.AngleVectors( NULL, &v, NULL );

	NewPos += v * ev->GetDouble( 1 );
}

// exact rotate commands

void ScriptSlave::RotateXdownto( Event* ev )
{
	commandswaiting = true;

	NewAngles[ 0 ] = ev->GetFloat( 1 );
	if( NewAngles[ 0 ] > angles[ 0 ] )
	{
		NewAngles[ 0 ] -= 360;
	}
}

void ScriptSlave::RotateYdownto( Event* ev )
{
	commandswaiting = true;

	NewAngles[ 1 ] = ev->GetFloat( 1 );
	if( NewAngles[ 1 ] > angles[ 1 ] )
	{
		NewAngles[ 1 ] -= 360;
	}
}

void ScriptSlave::RotateZdownto( Event* ev )
{
	commandswaiting = true;

	NewAngles[ 2 ] = ev->GetFloat( 1 );
	if( NewAngles[ 2 ] > angles[ 2 ] )
	{
		NewAngles[ 2 ] -= 360;
	}
}

void ScriptSlave::RotateAxisdownto( Event* ev )
{
	int axis;
	commandswaiting = true;

	axis = ev->GetInteger( 1 );
	NewAngles[ axis ] = ev->GetFloat( 2 );
	if( NewAngles[ axis ] > angles[ axis ] )
	{
		NewAngles[ axis ] -= 360;
	}
}

void ScriptSlave::RotateXupto( Event* ev )
{
	commandswaiting = true;

	NewAngles[ 0 ] = ev->GetFloat( 1 );
	if( NewAngles[ 0 ] < angles[ 0 ] )
	{
		NewAngles[ 0 ] += 360;
	}
}

void ScriptSlave::RotateYupto( Event* ev )
{
	commandswaiting = true;

	NewAngles[ 1 ] = ev->GetFloat( 1 );
	if( NewAngles[ 1 ] < angles[ 1 ] )
	{
		NewAngles[ 1 ] += 360;
	}
}

void ScriptSlave::RotateZupto( Event* ev )
{
	commandswaiting = true;

	NewAngles[ 2 ] = ev->GetFloat( 1 );
	if( NewAngles[ 2 ] < angles[ 2 ] )
	{
		NewAngles[ 2 ] += 360;
	}
}

void ScriptSlave::RotateAxisupto( Event* ev )
{
	int axis;
	commandswaiting = true;

	axis = ev->GetInteger( 1 );
	NewAngles[ axis ] = ev->GetFloat( 2 );
	if( NewAngles[ axis ] < angles[ axis ] )
	{
		NewAngles[ axis ] += 360;
	}
}

// full vector rotation

void ScriptSlave::Rotatedownto( Event* ev )
{
	Vector ang;
	commandswaiting = true;

	ang = ev->GetVector( 1 );

	NewAngles[ 0 ] = ang[ 0 ];
	if( NewAngles[ 0 ] > angles[ 0 ] )
	{
		NewAngles[ 0 ] -= 360;
	}
	NewAngles[ 1 ] = ang[ 1 ];
	if( NewAngles[ 1 ] > angles[ 1 ] )
	{
		NewAngles[ 1 ] -= 360;
	}
	NewAngles[ 2 ] = ang[ 2 ];
	if( NewAngles[ 2 ] > angles[ 2 ] )
	{
		NewAngles[ 2 ] -= 360;
	}
}

void ScriptSlave::Rotateupto( Event* ev )
{
	Vector ang;
	commandswaiting = true;

	ang = ev->GetVector( 1 );

	NewAngles[ 0 ] = ang[ 0 ];
	if( NewAngles[ 0 ] < angles[ 0 ] )
	{
		NewAngles[ 0 ] += 360;
	}
	NewAngles[ 1 ] = ang[ 1 ];
	if( NewAngles[ 1 ] < angles[ 1 ] )
	{
		NewAngles[ 1 ] += 360;
	}
	NewAngles[ 2 ] = ang[ 2 ];
	if( NewAngles[ 2 ] < angles[ 2 ] )
	{
		NewAngles[ 2 ] += 360;
	}
}

void ScriptSlave::Rotateto( Event* ev )
{
	Vector ang;
	commandswaiting = true;

	ang = ev->GetVector( 1 );

	NewAngles = ang;
}

// Relative rotate commands

void ScriptSlave::RotateXdown( Event* ev )
{
	commandswaiting = true;
	NewAngles[ 0 ] = angles[ 0 ] - ev->GetFloat( 1 );
}

void ScriptSlave::RotateYdown( Event* ev )
{
	commandswaiting = true;
	NewAngles[ 1 ] = angles[ 1 ] - ev->GetFloat( 1 );
}

void ScriptSlave::RotateZdown( Event* ev )
{
	commandswaiting = true;
	NewAngles[ 2 ] = angles[ 2 ] - ev->GetFloat( 1 );
}

void ScriptSlave::RotateAxisdown( Event* ev )
{
	int axis;
	commandswaiting = true;

	axis = ev->GetInteger( 1 );
	NewAngles[ axis ] = angles[ axis ] - ev->GetFloat( 2 );
}

void ScriptSlave::RotateXup( Event* ev )
{
	commandswaiting = true;
	NewAngles[ 0 ] = angles[ 0 ] + ev->GetFloat( 1 );
}

void ScriptSlave::RotateYup( Event* ev )
{
	commandswaiting = true;
	NewAngles[ 1 ] = angles[ 1 ] + ev->GetFloat( 1 );
}

void ScriptSlave::RotateZup( Event* ev )
{
	commandswaiting = true;
	NewAngles[ 2 ] = angles[ 2 ] + ev->GetFloat( 1 );
}

void ScriptSlave::RotateAxisup( Event* ev )
{
	int axis;
	commandswaiting = true;

	axis = ev->GetInteger( 1 );
	NewAngles[ axis ] = angles[ axis ] + ev->GetFloat( 2 );
}

void ScriptSlave::RotateX( Event* ev )
{
	avelocity[ 0 ] = ev->GetFloat( 1 );
}

void ScriptSlave::RotateY( Event* ev )
{
	avelocity[ 1 ] = ev->GetFloat( 1 );
}

void ScriptSlave::RotateZ( Event* ev )
{
	avelocity[ 2 ] = ev->GetFloat( 1 );
}

void ScriptSlave::RotateAxis( Event* ev )
{
	int axis;

	axis = ev->GetInteger( 1 );
	avelocity[ axis ] = ev->GetFloat( 2 );
}


void ScriptSlave::OnTouch( Event* ev )
{
	const char* jumpto;

	touchlabel = "";

	jumpto = ev->GetString( 1 );
	touchthread = ev->GetThread();

	assert( jumpto && touchthread );

	if( touchthread && !touchthread->labelExists( jumpto ) )
	{
		ev->Error( "Label '%s' not found", jumpto );
		return;
	}

	touchlabel = jumpto;
}

void ScriptSlave::NoTouch( Event* ev )
{
	touchlabel = "";
}

void ScriptSlave::TouchFunc( Event* ev )
{
	Event* e;
	Entity* other;

	if( touchlabel.length() )
	{
		// since we use a SafePtr, the thread pointer will be NULL if the thread has ended
		// so we should just clear our label and continue
		if( !touchthread )
		{
			touchlabel = "";
			return;
		}

		other = ev->GetEntity( 1 );

		e = new Event( EV_ScriptThread_Callback );
		e->AddEntity( this );
		e->AddString( touchlabel );
		e->AddEntity( other );
		touchthread->ProcessEvent( e );
	}
}

void ScriptSlave::OnBlock( Event* ev )
{
	const char* jumpto;

	blocklabel = "";

	jumpto = ev->GetString( 1 );
	blockthread = ev->GetThread();

	assert( jumpto && blockthread );

	if( blockthread && !blockthread->labelExists( jumpto ) )
	{
		ev->Error( "Label '%s' not found", jumpto );
		return;
	}

	blocklabel = jumpto;
}

void ScriptSlave::NoBlock( Event* ev )
{
	blocklabel = "";
}

void ScriptSlave::BlockFunc( Event* ev )
{
	Event* e;
	Entity* other;

	other = ev->GetEntity( 1 );
	if( level.time >= attack_finished )
	{
		attack_finished = level.time + ( float )0.5;
		if( dmg != 0 )
		{
			other->Damage( this, this, dmg, origin, vec_zero, vec_zero, 0, 0, MOD_CRUSH, -1, -1, 1.0f );
		}
	}

	if( blocklabel.length() )
	{
		// since we use a SafePtr, the thread pointer will be NULL if the thread has ended
		// so we should just clear our label and continue
		if( !blockthread )
		{
			blocklabel = "";
			return;
		}

		e = new Event( EV_ScriptThread_Callback );
		e->AddEntity( this );
		e->AddString( blocklabel );
		e->AddEntity( other );
		blockthread->ProcessEvent( e );
	}
}

void ScriptSlave::OnTrigger( Event* ev )
{
	const char* jumpto;

	triggerlabel = "";

	jumpto = ev->GetString( 1 );
	triggerthread = ev->GetThread();

	assert( jumpto && triggerthread );

	if( triggerthread && !triggerthread->labelExists( jumpto ) )
	{
		ev->Error( "Label '%s' not found", jumpto );
		return;
	}

	triggerlabel = jumpto;
}

void ScriptSlave::NoTrigger( Event* ev )
{
	triggerlabel = "";
}

void ScriptSlave::TriggerFunc( Event* ev )
{
	Event* e;
	Entity* other;

	if( triggerlabel.length() )
	{
		// since we use a SafePtr, the thread pointer will be NULL if the thread has ended
		// so we should just clear our label and continue
		if( !triggerthread )
		{
			triggerlabel = "";
			return;
		}

		other = ev->GetEntity( 1 );

		e = new Event( EV_ScriptThread_Callback );
		e->AddEntity( this );
		e->AddString( triggerlabel );
		e->AddEntity( other );

		triggerthread->ProcessEvent( e );
	}
}

void ScriptSlave::OnUse( Event* ev )
{
	const char* jumpto;

	uselabel = "";

	jumpto = ev->GetString( 1 );
	usethread = ev->GetThread();

	assert( jumpto && usethread );

	if( usethread && !usethread->labelExists( jumpto ) )
	{
		ev->Error( "Label '%s' not found", jumpto );
		return;
	}

	uselabel = jumpto;
}

void ScriptSlave::NoUse( Event* ev )
{
	uselabel = "";
}

void ScriptSlave::UseFunc( Event* ev )
{
	Event* e;
	Entity* other;

	other = ev->GetEntity( 1 );

	if( key.length() )
	{
		if( !other->isSubclassOf( Sentient ) || !( ( ( Sentient* )other )->HasItem( key.c_str() ) ) )
		{
			Item*        item;
			ClassDef*       cls;

			cls = getClass( key.c_str() );
			if( !cls )
			{
				gi.dprintf( "No item named '%s'\n", key.c_str() );
				return;
			}
			item = ( Item* )cls->newInstance();
			item->CancelEventsOfType( EV_Item_DropToFloor );
			item->CancelEventsOfType( EV_Remove );
			item->ProcessPendingEvents();
			gi.centerprintf( other->edict, "jcx yv 20 string \"You need this item:\" jcx yv -20 icon %d", item->GetIconIndex() );
			delete item;
			return;
		}
	}

	if( uselabel.length() )
	{
		ScriptVariableList* vars;

		// since we use a SafePtr, the thread pointer will be NULL if the thread has ended
		// so we should just clear our label and continue
		if( !usethread )
		{
			uselabel = "";
			return;
		}

		e = new Event( EV_ScriptThread_Callback );
		e->AddEntity( this );
		e->AddString( uselabel );
		e->AddEntity( other );

		vars = usethread->Vars();
		vars->SetVariable( "other", other );
		if( key.length() )
		{
			vars->SetVariable( "key", key.c_str() );
		}
		usethread->ProcessEvent( e );
	}
}

void ScriptSlave::OnDamage( Event* ev )
{
	const char* jumpto;

	damagelabel = "";

	jumpto = ev->GetString( 1 );
	damagethread = ev->GetThread();

	assert( jumpto && damagethread );

	if( damagethread && !damagethread->labelExists( jumpto ) )
	{
		ev->Error( "Label '%s' not found", jumpto );
		return;
	}

	damagelabel = jumpto;
}

void ScriptSlave::NoDamage( Event* ev )
{
	damagelabel = "";
}

void ScriptSlave::DamageFunc( Event* ev )
{
	Event*          e;
	Entity*     inflictor;
	Entity*     attacker;
	int damage;
	Vector position;
	Vector direction;
	ScriptVariableList* vars;

	if( damagelabel.length() )
	{
		// since we use a SafePtr, the thread pointer will be NULL if the thread has ended
		// so we should just clear our label and continue
		if( !damagethread )
		{
			damagelabel = "";
			return;
		}

		attacker    = ev->GetEntity( 3 );

		e = new Event( EV_ScriptThread_Callback );
		e->AddEntity( this );
		e->AddString( damagelabel );
		e->AddEntity( attacker );

		damage      = ev->GetInteger( 1 );
		inflictor   = ev->GetEntity( 2 );
		position        = ev->GetVector( 4 );
		direction   = ev->GetVector( 5 );

		vars = damagethread->Vars();
		vars->SetVariable( "damage", damage );
		vars->SetVariable( "inflictor", inflictor );
		vars->SetVariable( "attacker", attacker );
		vars->SetVariable( "position", position );
		vars->SetVariable( "direction", direction );
		damagethread->ProcessEvent( e );
	}
}

void ScriptSlave::SetDamage( Event* ev )
{
	dmg = ev->GetInteger( 1 );
}

void ScriptSlave::CreatePath( SplinePath* path, splinetype_t type )
{
	SplinePath* node;

	if( !splinePath )
	{
		splinePath = new BSplineDLL;
	}

	splinePath->Clear();
	splinePath->SetType( type );

	node = path;
	while( node != NULL )
	{
		splinePath->AppendControlPoint( node->worldorigin, node->angles, node->speed );
		node = node->GetNext();

		if( node == path )
		{
			break;
		}
	}
}

void ScriptSlave::FollowPath( Event* ev )
{
	int i, argnum;
	Entity* ent;
	const char* token;
	SplinePath* path;
	qboolean clamp;
	float starttime;


	ent = ev->GetEntity( 1 );
	argnum = 2;
	starttime = -2;
	clamp = true;
	ignoreangles = false;
	splineangles = true;
	for( i = argnum; i <= ev->NumArgs(); i++ )
	{
		token = ev->GetString( i );
		if( !Q_stricmp( token, "ignoreangles" ) )
		{
			ignoreangles = true;
		}
		if( !Q_stricmp( token, "normalangles" ) )
		{
			splineangles = false;
		}
		else if( !Q_stricmp( token, "loop" ) )
		{
			clamp = false;
		}
		else if( IsNumeric( token ) )
		{
			starttime = Sinatof( token );
		}
		else
		{
			ev->Error( "Unknown followpath command %s.", token );
		}
	}
	if( ent && ent->isSubclassOf( SplinePath ) )
	{
		commandswaiting = true;
		path = ( SplinePath* )ent;
		if( clamp )
			CreatePath( path, SPLINE_CLAMP );
		else
			CreatePath( path, SPLINE_LOOP );
		splineTime = starttime;
		CancelEventsOfType( EV_ScriptSlave_FollowingPath );
		avelocity = vec_zero;
		velocity = vec_zero;
	}
}

void ScriptSlave::EndPath( Event* ev )
{
	if( !splinePath )
		return;

	delete splinePath;
	splinePath = NULL;
	velocity = vec_zero;
	avelocity = vec_zero;
}

void ScriptSlave::FollowingPath( Event* ev )
{
	Vector pos;
	Vector orient;
	float speed_multiplier;

	if( !splinePath )
		return;

	if( ( splinePath->GetType() == SPLINE_CLAMP ) && ( splineTime > ( splinePath->EndPoint() - 2 ) ) )
	{
		delete splinePath;
		splinePath = NULL;
		velocity = vec_zero;
		avelocity = vec_zero;
		ProcessEvent( EV_ScriptSlave_MoveDone );
		return;
	}

	speed_multiplier = splinePath->Eval( splineTime, pos, orient );

	splineTime += FRAMETIME * speed_multiplier;

	velocity = ( pos - origin ) * ( 1 / FRAMETIME );
	if( !ignoreangles )
	{
		if( splineangles )
		{
			avelocity = ( orient - angles ) * ( 1 / FRAMETIME );
		}
		else
		{
			float len;

			len = velocity.length();
			if( len > 0.05 )
			{
				Vector ang;
				Vector dir;
				float aroll;

				aroll = avelocity[ ROLL ];
				dir = velocity * ( 1 / len );
				ang = dir.toAngles();
				ang[ PITCH ] = -ang[ PITCH ];
				avelocity = ( ang - angles ) * ( 1 / FRAMETIME );
				avelocity[ ROLL ] = aroll;
			}
			else
				avelocity = vec_zero;
		}
	}
	PostEvent( EV_ScriptSlave_FollowingPath, FRAMETIME );
}

void ScriptSlave::Explode( Event* ev )
{
	float radius;
	float scale;
	float damage;

	if( ev->NumArgs() )
	{
		damage = ev->GetFloat( 1 );
		if( ev->NumArgs() > 1 )
		{
			scale = ev->GetFloat( 2 );
		}
		else
		{
			radius = size.length() * 0.5f;
			scale = radius * 0.02f;
		}
		CreateExplosion( worldorigin, damage, scale, true, this, this, this );
	}
	else
	{
		radius = size.length() * 0.5f;
		CreateExplosion( worldorigin, radius * 3, radius * 0.02f, true, this, this, this );
	}
}

void ScriptSlave::NotShootable( Event* ev )
{
	edict->svflags &= ~SVF_SHOOTABLE;
}


/*****************************************************************************/
/*SINED func_scriptmodel (0 .5 .8) (0 0 0) (0 0 0) NOT_SOLID

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

CLASS_DECLARATION( ScriptSlave, ScriptModel, "func_scriptmodel" );

ResponseDef ScriptModel::Responses[] =
{
	{ &EV_Gib, ( Response )& ScriptModel::GibEvent },
	{ NULL, NULL },
};

ScriptModel::ScriptModel()
{
	const char* animname;
	const char* skinname;
	Vector defangles;

	if( ( gi.IsModel( edict->s.modelindex ) ) && !mins.length() && !maxs.length() )
	{
		gi.CalculateBounds( edict->s.modelindex, edict->s.scale, mins.vec3(), maxs.vec3() );
	}
	// angles
	defangles = Vector( 0, G_GetFloatArg( "angle", 0 ), 0 );
	if( defangles.y == -1 )
	{
		defangles = Vector( -90, 0, 0 );
	}
	else if( defangles.y == -2 )
	{
		defangles = Vector( 90, 0, 0 );
	}
	angles = G_GetVectorArg( "angles", defangles );
	setAngles( angles );

	animname = G_GetSpawnArg( "anim" );
	if( animname && strlen( animname ) && gi.IsModel( edict->s.modelindex ) )
	{
		int animnum;

		animnum = gi.Anim_NumForName( edict->s.modelindex, animname );
		if( animnum >= 0 )
			NextAnim( animnum );
		StartAnimating();
	}
	skinname = G_GetSpawnArg( "skin" );
	if( skinname && strlen( skinname ) && gi.IsModel( edict->s.modelindex ) )
	{
		int skinnum;

		skinnum = gi.Skin_NumForName( edict->s.modelindex, skinname );
		if( skinnum >= 0 )
			edict->s.skinnum = skinnum;
	}
}

void ScriptModel::GibEvent( Event* ev )
{
	int num, power;
	float scale;
	str gibmodel;

	setSolidType( SOLID_NOT );
	hideModel();

	if( !sv_gibs->value || parentmode->value )
	{
		PostEvent( EV_Remove, 0 );
		return;
	}

	num = ev->GetInteger( 1 );
	power = ev->GetInteger( 2 );
	scale = ev->GetFloat( 3 );
	gibmodel = ev->GetString( 4 );

	power = -power;

	if( gibmodel == "organic" )
		CreateGibs( this, power, scale, num );
	else if( gibmodel == "feather" )
		CreateGibs( this, power, scale, num, "feather.def" );

	PostEvent( EV_Remove, 0 );
}

/*****************************************************************************/
/*SINED func_scriptorigin (0 .5 .8) (-8 -8 -8) (8 8 8)

   Used as an alternate origin for objects.  Bind the object to the func_scriptorigin
   in order to simulate changing that object's origin.
 *****************************************************************************/

CLASS_DECLARATION( ScriptSlave, ScriptOrigin, "func_scriptorigin" );

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

ScriptOrigin::ScriptOrigin()
{
	edict->svflags &= ~SVF_SHOOTABLE;
	setSolidType( SOLID_NOT );
}

/*****************************************************************************/
/*SINED func_volumetric (0 .5 .8) ?

   Use this to make non-solid volumes.  You still need to set up the surface
   properties with the "add" flag.
 *****************************************************************************/

CLASS_DECLARATION( ScriptSlave, ScriptVolumetric, "func_volumetric" );

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

ScriptVolumetric::ScriptVolumetric()
{
	edict->svflags &= ~SVF_SHOOTABLE;
	setSolidType( SOLID_NOT );
}
