859 lines
16 KiB
C++
859 lines
16 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Logfile:: /Quake 2 Engine/Sin/code/game/bspline.cpp $
|
|
// $Revision:: 14 $
|
|
// $Author:: Markd $
|
|
// $Date:: 8/07/99 1:53p $
|
|
//
|
|
// 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/bspline.cpp $
|
|
//
|
|
// 14 8/07/99 1:53p Markd
|
|
// Fixed a bunch of more code for version 1.06
|
|
//
|
|
// 13 5/19/99 11:30a Markd
|
|
// Added new camera support
|
|
//
|
|
// 12 10/19/98 9:51p Jimdose
|
|
// fixed savegame bugs with bspline
|
|
//
|
|
// 11 10/10/98 9:12p Markd
|
|
// Fixed angle errors with bsplines
|
|
//
|
|
// 10 8/15/98 2:39p Markd
|
|
// fixed up some bspline stuff
|
|
//
|
|
// 9 7/11/98 6:31p Markd
|
|
// removed valid orientation, simplified code
|
|
//
|
|
// 8 7/10/98 1:11p Markd
|
|
// Added additional two paramter append control point
|
|
//
|
|
// 7 7/08/98 12:41p Markd
|
|
// Added speed and quaternion support
|
|
//
|
|
// 6 7/02/98 9:48p Markd
|
|
// added orientation
|
|
//
|
|
// 5 5/26/98 7:55p Jimdose
|
|
// Added Drawcurve with offset
|
|
//
|
|
// 4 5/07/98 10:40p Jimdose
|
|
// Added spline type for selecting between looping and non-looping curves
|
|
//
|
|
// 3 5/05/98 2:37p Jimdose
|
|
// Added code to allow spline loop and clamping the spline start and end
|
|
//
|
|
// 2 5/03/98 4:42p Jimdose
|
|
// Added file to Sin
|
|
//
|
|
// DESCRIPTION:
|
|
// Uniform non-rational bspline class.
|
|
//
|
|
|
|
#include "g_local.h"
|
|
#include "BSpline.h"
|
|
|
|
void BSpline::Set
|
|
(
|
|
Vector *control_points_,
|
|
int num_control_points_,
|
|
splinetype_t type
|
|
)
|
|
|
|
{
|
|
int i;
|
|
|
|
SetType( type );
|
|
|
|
has_orientation = false;
|
|
|
|
if ( control_points )
|
|
{
|
|
delete [] control_points;
|
|
control_points = NULL;
|
|
}
|
|
|
|
num_control_points = num_control_points_;
|
|
if ( num_control_points )
|
|
{
|
|
control_points = new BSplineControlPoint[ num_control_points ];
|
|
assert( control_points );
|
|
|
|
for( i = 0; i < num_control_points; i++ )
|
|
{
|
|
control_points[ i ].Set( control_points_[ i ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
void BSpline::Set
|
|
(
|
|
Vector *control_points_,
|
|
Vector *control_orients_,
|
|
float *control_speeds_,
|
|
int num_control_points_,
|
|
splinetype_t type
|
|
)
|
|
|
|
{
|
|
int i;
|
|
|
|
SetType( type );
|
|
|
|
has_orientation = true;
|
|
|
|
if ( control_points )
|
|
{
|
|
delete [] control_points;
|
|
control_points = NULL;
|
|
}
|
|
|
|
num_control_points = num_control_points_;
|
|
if ( num_control_points )
|
|
{
|
|
control_points = new BSplineControlPoint[ num_control_points ];
|
|
assert( control_points );
|
|
|
|
for( i = 0; i < num_control_points; i++ )
|
|
{
|
|
control_points[ i ].Set( control_points_[ i ], control_orients_[ i ], control_speeds_[ i ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
void BSpline::Clear
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
if( control_points )
|
|
{
|
|
delete [] control_points;
|
|
control_points = NULL;
|
|
}
|
|
num_control_points = 0;
|
|
has_orientation = false;
|
|
}
|
|
|
|
inline float BSpline::EvalNormal
|
|
(
|
|
float u,
|
|
Vector& pos,
|
|
Vector& orient
|
|
)
|
|
|
|
{
|
|
int segment_id;
|
|
float B[ 4 ];
|
|
float tmp;
|
|
float u_2;
|
|
float u_3;
|
|
Vector ang;
|
|
float roll;
|
|
float speed;
|
|
|
|
segment_id = ( int )u;
|
|
if ( segment_id < 0 )
|
|
{
|
|
segment_id = 0;
|
|
}
|
|
if ( segment_id > num_control_points - 4 )
|
|
{
|
|
segment_id = num_control_points - 4;
|
|
}
|
|
u -= ( float )segment_id;
|
|
|
|
u_2 = u * u;
|
|
u_3 = u * u_2;
|
|
|
|
tmp = 1 - u;
|
|
B[ 0 ] = ( tmp * tmp * tmp ) * ( 1.0f / 6.0f );
|
|
B[ 1 ] = ( 3.0f * u_3 - 6.0f * u_2 + 4.0f ) * ( 1.0f / 6.0f );
|
|
B[ 2 ] = ( -3.0f * u_3 + 3.0f * u_2 + 3.0f * u + 1 ) * ( 1.0f / 6.0f );
|
|
B[ 3 ] = u_3 * ( 1.0f / 6.0f );
|
|
|
|
pos =
|
|
*control_points[ 0 + segment_id ].GetPosition() * B[ 0 ] +
|
|
*control_points[ 1 + segment_id ].GetPosition() * B[ 1 ] +
|
|
*control_points[ 2 + segment_id ].GetPosition() * B[ 2 ] +
|
|
*control_points[ 3 + segment_id ].GetPosition() * B[ 3 ];
|
|
|
|
ang =
|
|
*control_points[ 0 + segment_id ].GetOrientation() * B[ 0 ] +
|
|
*control_points[ 1 + segment_id ].GetOrientation() * B[ 1 ] +
|
|
*control_points[ 2 + segment_id ].GetOrientation() * B[ 2 ] +
|
|
*control_points[ 3 + segment_id ].GetOrientation() * B[ 3 ];
|
|
|
|
roll =
|
|
*control_points[ 0 + segment_id ].GetRoll() * B[ 0 ] +
|
|
*control_points[ 1 + segment_id ].GetRoll() * B[ 1 ] +
|
|
*control_points[ 2 + segment_id ].GetRoll() * B[ 2 ] +
|
|
*control_points[ 3 + segment_id ].GetRoll() * B[ 3 ];
|
|
|
|
speed =
|
|
*control_points[ 0 + segment_id ].GetSpeed() * B[ 0 ] +
|
|
*control_points[ 1 + segment_id ].GetSpeed() * B[ 1 ] +
|
|
*control_points[ 2 + segment_id ].GetSpeed() * B[ 2 ] +
|
|
*control_points[ 3 + segment_id ].GetSpeed() * B[ 3 ];
|
|
|
|
orient = ang.toAngles();
|
|
orient[ ROLL ] = roll;
|
|
|
|
return speed;
|
|
}
|
|
|
|
inline float BSpline::EvalLoop
|
|
(
|
|
float t,
|
|
Vector& pos,
|
|
Vector& orient
|
|
)
|
|
|
|
{
|
|
Vector retval;
|
|
Vector ang;
|
|
float speed;
|
|
float roll;
|
|
int segment_id;
|
|
int next_id;
|
|
float B[ 4 ];
|
|
float tmp;
|
|
float u;
|
|
float u_2;
|
|
float u_3;
|
|
int i;
|
|
int j;
|
|
|
|
segment_id = ( int )floor( t );
|
|
u = t - floor( t );
|
|
|
|
segment_id %= num_control_points;
|
|
if ( segment_id < 0 )
|
|
{
|
|
segment_id += num_control_points;
|
|
}
|
|
|
|
u_2 = u * u;
|
|
u_3 = u * u_2;
|
|
|
|
tmp = 1 - u;
|
|
B[ 0 ] = ( tmp * tmp * tmp ) * ( 1.0f / 6.0f );
|
|
B[ 1 ] = ( 3.0f * u_3 - 6.0f * u_2 + 4.0f ) * ( 1.0f / 6.0f );
|
|
B[ 2 ] = ( -3.0f * u_3 + 3.0f * u_2 + 3.0f * u + 1 ) * ( 1.0f / 6.0f );
|
|
B[ 3 ] = u_3 * ( 1.0f / 6.0f );
|
|
|
|
speed = 0;
|
|
roll = 0;
|
|
|
|
for( i = 0, j = segment_id; i < 4; i++, j++ )
|
|
{
|
|
if ( j >= num_control_points )
|
|
{
|
|
j -= ( num_control_points - loop_control_point );
|
|
}
|
|
|
|
retval += *control_points[ j ].GetPosition() * B[ i ];
|
|
ang += *control_points[ j ].GetOrientation() * B[ i ];
|
|
speed += *control_points[ j ].GetSpeed() * B[ i ];
|
|
roll += *control_points[ j ].GetRoll() * B[ i ];
|
|
}
|
|
|
|
pos = retval;
|
|
|
|
next_id = segment_id + 1;
|
|
if ( next_id >= num_control_points )
|
|
{
|
|
next_id -= ( num_control_points - loop_control_point );
|
|
}
|
|
orient = ang.toAngles();
|
|
orient[ ROLL ] = roll;
|
|
|
|
return speed;
|
|
}
|
|
|
|
inline float BSpline::EvalClamp
|
|
(
|
|
float t,
|
|
Vector& pos,
|
|
Vector& orient
|
|
)
|
|
|
|
{
|
|
Vector retval;
|
|
Vector ang;
|
|
int segment_id;
|
|
int next_id;
|
|
float B[ 4 ];
|
|
float tmp;
|
|
float u;
|
|
float u_2;
|
|
float u_3;
|
|
int i;
|
|
int j;
|
|
float speed;
|
|
float roll;
|
|
|
|
segment_id = ( int )floor( t );
|
|
u = t - floor( t );
|
|
|
|
u_2 = u * u;
|
|
u_3 = u * u_2;
|
|
|
|
tmp = 1 - u;
|
|
B[ 0 ] = ( tmp * tmp * tmp ) * ( 1.0f / 6.0f );
|
|
B[ 1 ] = ( 3.0f * u_3 - 6.0f * u_2 + 4.0f ) * ( 1.0f / 6.0f );
|
|
B[ 2 ] = ( -3.0f * u_3 + 3.0f * u_2 + 3.0f * u + 1 ) * ( 1.0f / 6.0f );
|
|
B[ 3 ] = u_3 * ( 1.0f / 6.0f );
|
|
|
|
speed = 0;
|
|
roll = 0;
|
|
for( i = 0; i < 4; i++, segment_id++ )
|
|
{
|
|
j = segment_id;
|
|
if ( j < 0 )
|
|
{
|
|
j = 0;
|
|
}
|
|
else if ( j >= num_control_points )
|
|
{
|
|
j = num_control_points - 1;
|
|
}
|
|
|
|
retval += *control_points[ j ].GetPosition() * B[ i ];
|
|
ang += *control_points[ j ].GetOrientation() * B[ i ];
|
|
speed += *control_points[ j ].GetSpeed() * B[ i ];
|
|
roll += *control_points[ j ].GetRoll() * B[ i ];
|
|
}
|
|
|
|
pos = retval;
|
|
|
|
next_id = segment_id + 1;
|
|
if ( segment_id < 0 )
|
|
{
|
|
segment_id = 0;
|
|
}
|
|
if ( segment_id >= num_control_points )
|
|
{
|
|
segment_id = num_control_points - 1;
|
|
}
|
|
if ( next_id < 0 )
|
|
{
|
|
next_id = 0;
|
|
}
|
|
if ( next_id >= num_control_points )
|
|
{
|
|
next_id = num_control_points - 1;
|
|
}
|
|
orient = ang.toAngles();
|
|
orient[ ROLL ] = roll;
|
|
|
|
return speed;
|
|
}
|
|
|
|
|
|
Vector BSpline::Eval
|
|
(
|
|
float u
|
|
)
|
|
|
|
{
|
|
Vector pos;
|
|
Vector orient;
|
|
|
|
switch( curvetype )
|
|
{
|
|
default:
|
|
case SPLINE_NORMAL :
|
|
EvalNormal( u, pos, orient );
|
|
break;
|
|
|
|
case SPLINE_CLAMP:
|
|
EvalClamp( u, pos, orient );
|
|
break;
|
|
|
|
case SPLINE_LOOP:
|
|
EvalLoop( u, pos, orient );
|
|
break;
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
float BSpline::Eval
|
|
(
|
|
float u,
|
|
Vector &pos,
|
|
Vector &orient
|
|
)
|
|
|
|
{
|
|
switch( curvetype )
|
|
{
|
|
default:
|
|
case SPLINE_NORMAL :
|
|
return EvalNormal( u, pos, orient );
|
|
break;
|
|
|
|
case SPLINE_CLAMP:
|
|
return EvalClamp( u, pos, orient );
|
|
break;
|
|
|
|
case SPLINE_LOOP:
|
|
return EvalLoop( u, pos, orient );
|
|
break;
|
|
}
|
|
}
|
|
|
|
void BSpline::DrawControlSegments
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
int i;
|
|
|
|
G_BeginLine();
|
|
for( i = 0; i < num_control_points; i++ )
|
|
{
|
|
G_Vertex( *control_points[ i ].GetPosition() );
|
|
}
|
|
G_EndLine();
|
|
}
|
|
|
|
void BSpline::DrawCurve
|
|
(
|
|
int num_subdivisions
|
|
)
|
|
|
|
{
|
|
float u;
|
|
float du;
|
|
|
|
du = 1.0f / ( float )num_subdivisions;
|
|
|
|
G_BeginLine();
|
|
for( u = 0.0f; u <= ( float )num_control_points; u += du )
|
|
{
|
|
G_Vertex( ( Vector )Eval( u ) );
|
|
}
|
|
G_EndLine();
|
|
}
|
|
|
|
void BSpline::DrawCurve
|
|
(
|
|
Vector offset,
|
|
int num_subdivisions
|
|
)
|
|
|
|
{
|
|
float u;
|
|
float du;
|
|
|
|
du = 1.0f / ( float )num_subdivisions;
|
|
|
|
G_BeginLine();
|
|
for( u = 0.0f; u <= ( float )num_control_points; u += du )
|
|
{
|
|
G_Vertex( offset + ( Vector )Eval( u ) );
|
|
}
|
|
G_EndLine();
|
|
}
|
|
|
|
void BSpline::AppendControlPoint
|
|
(
|
|
const Vector& new_control_point
|
|
)
|
|
|
|
{
|
|
BSplineControlPoint *old_control_points;
|
|
int i;
|
|
|
|
old_control_points = control_points;
|
|
num_control_points++;
|
|
|
|
control_points = new BSplineControlPoint[num_control_points];
|
|
assert( control_points );
|
|
|
|
if ( old_control_points )
|
|
{
|
|
for( i = 0; i < num_control_points - 1; i++ )
|
|
{
|
|
control_points[ i ] = old_control_points[ i ];
|
|
}
|
|
delete [] old_control_points;
|
|
}
|
|
|
|
control_points[ num_control_points - 1 ].Set( new_control_point );
|
|
}
|
|
|
|
void BSpline::AppendControlPoint
|
|
(
|
|
const Vector& new_control_point,
|
|
const float& speed
|
|
)
|
|
|
|
{
|
|
BSplineControlPoint *old_control_points;
|
|
int i;
|
|
|
|
old_control_points = control_points;
|
|
num_control_points++;
|
|
|
|
control_points = new BSplineControlPoint[num_control_points];
|
|
assert( control_points );
|
|
|
|
if ( old_control_points )
|
|
{
|
|
for( i = 0; i < num_control_points - 1; i++ )
|
|
{
|
|
control_points[ i ] = old_control_points[ i ];
|
|
}
|
|
delete [] old_control_points;
|
|
}
|
|
|
|
control_points[ num_control_points - 1 ].Set( new_control_point, speed );
|
|
}
|
|
|
|
void BSpline::AppendControlPoint
|
|
(
|
|
const Vector& new_control_point,
|
|
const Vector& new_control_orient,
|
|
const float& new_control_speed
|
|
)
|
|
|
|
{
|
|
BSplineControlPoint *old_control_points;
|
|
int i;
|
|
|
|
has_orientation = true;
|
|
|
|
old_control_points = control_points;
|
|
num_control_points++;
|
|
|
|
control_points = new BSplineControlPoint[num_control_points];
|
|
assert( control_points );
|
|
|
|
if ( old_control_points )
|
|
{
|
|
for( i = 0; i < num_control_points - 1; i++ )
|
|
{
|
|
control_points[ i ] = old_control_points[ i ];
|
|
}
|
|
delete [] old_control_points;
|
|
}
|
|
|
|
control_points[ num_control_points - 1 ].Set( new_control_point, new_control_orient, new_control_speed );
|
|
}
|
|
|
|
void BSpline::SetLoopPoint
|
|
(
|
|
const Vector& pos
|
|
)
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < num_control_points; i++ )
|
|
{
|
|
if ( pos == *control_points[ i ].GetPosition() )
|
|
{
|
|
loop_control_point = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int BSpline::PickControlPoint
|
|
(
|
|
const Vector& window_point,
|
|
float pick_size
|
|
)
|
|
|
|
{
|
|
int i;
|
|
float closest_dist_2;
|
|
int closest_index;
|
|
float dist_2;
|
|
Vector delta;
|
|
|
|
closest_index = -1;
|
|
closest_dist_2 = 1000000.0f;
|
|
for( i = 0; i < num_control_points; i++ )
|
|
{
|
|
delta = window_point - *control_points[ i ].GetPosition();
|
|
dist_2 = delta * delta;
|
|
if ( dist_2 < closest_dist_2 )
|
|
{
|
|
closest_dist_2 = dist_2;
|
|
closest_index = i;
|
|
}
|
|
}
|
|
|
|
if ( pick_size * pick_size >= closest_dist_2 )
|
|
{
|
|
return closest_index;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
CLASS_DECLARATION( Entity, SplinePath, "info_splinepath" );
|
|
|
|
Event EV_SplinePath_Create( "SplinePath_create" );
|
|
Event EV_SplinePath_Loop( "loop", EV_CONSOLE );
|
|
Event EV_SplinePath_Speed( "speed" );
|
|
|
|
ResponseDef SplinePath::Responses[] =
|
|
{
|
|
{ &EV_SplinePath_Create, ( Response )SplinePath::CreatePath },
|
|
{ &EV_SplinePath_Loop, ( Response )SplinePath::SetLoop },
|
|
{ &EV_SplinePath_Speed, ( Response )SplinePath::SetSpeed },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
SplinePath::SplinePath()
|
|
{
|
|
owner = this;
|
|
next = NULL;
|
|
loop = NULL;
|
|
doWatch = false;
|
|
watchEnt = "";
|
|
|
|
loop_name = G_GetStringArg( "loop" );
|
|
angles = G_GetVectorArg( "angles" );
|
|
speed = G_GetFloatArg( "speed", 1 );
|
|
setMoveType( MOVETYPE_NONE );
|
|
setSolidType( SOLID_NOT );
|
|
hideModel();
|
|
|
|
if ( !LoadingSavegame )
|
|
{
|
|
PostEvent( EV_SplinePath_Create, 0 );
|
|
}
|
|
}
|
|
|
|
SplinePath::~SplinePath()
|
|
{
|
|
// disconnect from the chain
|
|
if ( owner != this )
|
|
{
|
|
owner->SetNext( next );
|
|
owner = this;
|
|
}
|
|
else if ( next )
|
|
{
|
|
next->SetPrev( NULL );
|
|
next = NULL;
|
|
}
|
|
|
|
assert( owner == this );
|
|
assert( next == NULL );
|
|
}
|
|
|
|
|
|
void SplinePath::CreatePath
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
const char *target;
|
|
int num;
|
|
|
|
// Make the path from the targetlist.
|
|
target = Target();
|
|
if ( target[ 0 ] )
|
|
{
|
|
if ( num = G_FindTarget( 0, target ) )
|
|
{
|
|
next = ( SplinePath * )G_GetEntity( num );
|
|
next->owner = this;
|
|
}
|
|
else
|
|
{
|
|
gi.error( "SplinePath::CreatePath: target %s not found\n", target );
|
|
}
|
|
}
|
|
if ( loop_name.length() )
|
|
{
|
|
if ( num = G_FindTarget( 0, loop_name.c_str() ) )
|
|
{
|
|
loop = ( SplinePath * )G_GetEntity( num );
|
|
}
|
|
}
|
|
}
|
|
|
|
SplinePath *SplinePath::GetNext
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return next;
|
|
}
|
|
|
|
SplinePath *SplinePath::GetLoop
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return loop;
|
|
}
|
|
|
|
void SplinePath::SetLoop
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
loop_name = ev->GetString( 1 );
|
|
}
|
|
|
|
void SplinePath::SetSpeed
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
speed = ev->GetFloat( 1 );
|
|
}
|
|
|
|
SplinePath *SplinePath::GetPrev
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
if ( owner == this )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return owner;
|
|
}
|
|
|
|
void SplinePath::SetNext
|
|
(
|
|
SplinePath *node
|
|
)
|
|
|
|
{
|
|
if ( next )
|
|
{
|
|
// remove ourselves from the chain
|
|
next->owner = next;
|
|
}
|
|
|
|
next = node;
|
|
if ( next )
|
|
{
|
|
// disconnect next from it's previous node
|
|
if ( next->owner != next )
|
|
{
|
|
next->owner->next = NULL;
|
|
}
|
|
next->owner = this;
|
|
}
|
|
}
|
|
|
|
void SplinePath::SetPrev
|
|
(
|
|
SplinePath *node
|
|
)
|
|
|
|
{
|
|
if ( owner != this )
|
|
{
|
|
owner->next = NULL;
|
|
}
|
|
|
|
if ( node && ( node != this ) )
|
|
{
|
|
// safely remove the node from its chain
|
|
if ( node->next )
|
|
{
|
|
node->next->owner = node->next;
|
|
}
|
|
node->next = this;
|
|
owner = node;
|
|
}
|
|
else
|
|
{
|
|
owner = this;
|
|
}
|
|
}
|
|
|
|
void SplinePath::SetWatch
|
|
(
|
|
const char *name
|
|
)
|
|
|
|
{
|
|
doWatch = true;
|
|
watchEnt = name;
|
|
}
|
|
|
|
void SplinePath::NoWatch
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
doWatch = true;
|
|
watchEnt = "";
|
|
}
|
|
|
|
Entity *SplinePath::GetWatch
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
const char *name;
|
|
int t;
|
|
|
|
name = watchEnt.c_str();
|
|
if ( name[ 0 ] == '$' )
|
|
{
|
|
t = G_FindTarget( 0, &name[ 1 ] );
|
|
if ( !t )
|
|
{
|
|
warning( "GetWatch", "Entity with targetname of '%s' not found", &name[ 1 ] );
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( name[ 0 ] != '*' )
|
|
{
|
|
warning( "GetWatch", "Expecting a '*'-prefixed entity number but found '%s'.", name );
|
|
return NULL;
|
|
}
|
|
|
|
if ( !IsNumeric( &name[ 1 ] ) )
|
|
{
|
|
warning( "GetWatch", "Expecting a numeric value but found '%s'.", &name[ 1 ] );
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
t = atoi( &name[ 1 ] );
|
|
}
|
|
}
|
|
|
|
if ( ( t < 0 ) || ( t > game.maxentities ) )
|
|
{
|
|
warning( "GetWatch", "%d out of valid range for entity.", t );
|
|
return NULL;
|
|
}
|
|
|
|
return G_GetEntity( t );
|
|
}
|